1

我必须在golang中创建一个类似于2级继承的替代品,即在一个包中,我有一个结构(A ),它被另一个包中的另一个结构( B )继承(嵌入为匿名字段),其对象将由“ main ”包使用。

现在,我为“B”(BPlease)创建了一个初始化方法,该方法返回 B 的对象(例如B_obj)。我可以在程序开始时从我的“主”包中调用这个初始化程序(BPlease )。

“B”的方法之一(比如HelloB () )在执行期间调用“A”的方法(比如HelloA() ),使用“B's”对象。

但我真正想要的是,类似于“A”的构造函数,它可以在“B”调用“A”的任何方法之前初始化其字段(最好是在“main”包中创建 B_obj 时)。

如何做到这一点?

我也尝试为“A”创建一个初始化程序(APlease)并调用它(BPlease)来获取“A”的对象(A_obj)。但是我发现这个对象没用,因为我不能利用它在“B”方法(HelloB())中调用“A”方法(HelloA())。如果有人能告诉我如何使用这个对象(A_obj),那就太好了。

这是一些代码来澄清我的查询:

    package A
    type A struct { whatever }
    func (A_obj *A) HelloA(){performs some operation...}           // a method of A()
    func APlease() A {
          return A{initialize A fields}
        }
-------------------------------------------------------------------------------
    package B
    type B struct {
      A
      B fields
    }

    func BPlease() B {
      return B{
      A_obj := APlease()                     // useless to me.... how to utilise this?
      initialize B fields}
    }

    func (B_obj *B) HelloB(){                            // a method of B{}
      call B_obj.HelloA()                         // valid as A is an anon field in B struct
      some other operations                       // but A's fields are not initialized for B_obj
...}         

---------------------------------------------------
package main

import "B"
import "A"

func main(){
  B_obj := B.BPlease()         // what I want is, calling this should initialize A's fields for B_obj as well so that when HelloB() calls B_obj.HelloA(), it utilises A's field that have been initialized.
}

我不能将所有字段值作为参数传递给 B_obj,因为有很多字段,而且,一些字段值是通过调用相同结构的方法生成的。

4

4 回答 4

7

不管任何人对没有继承的语言有什么看法:不,没有神奇的方法,比如“getter”或“setter”之类的。远程相关(魔法力量)可能是终结者,但在这种情况下它们肯定不会有帮助。

但是,让我建议停止在 Go 中编写语言 X。只需使用 Go。Go 不使用“类类”继承,Go 程序员(通常)也不应该使用。把 Go 想象成一个现代化的 C。没有多少 C 代码依赖于继承。(好的,我知道 GObject ;-)

于 2013-06-03T13:48:19.927 回答
3

一些元评论:“第一结构”和“第二结构”使得很难理解哪个是哪个。标记 A、B 和 C 等不同事物是使数学如此强大的工具。

这是您的问题吗:您有两种类型 A 和 B,B 嵌入了 A。您要确保 B 在 A 也已初始化的意义上“完全初始化”。

原始草图:

type A struct { whatever }
type B struct {
  A
  more stuff
}

func APlease(params for an A) A {
  return A{fields set up from params}
}

func BPlease(params forn an A and for an B) B {
  return B{
    A: APlease(stuff for A),
    more: set from params for B,
  }
}

BPlease应该这样做:您可以通过调用嵌入式 A 和 B 的其余部分的必要参数来请求正确设置B。

于 2013-06-03T15:29:17.740 回答
1

To expand on Volker's answer a bit, you should be able to call

func BPlease() B {
  a_obj := A.APlease() // initialize the fields of A like normal
  b_obj := B{} // create a B, whose anonymous fields are not initialized yet

  b_obj.A = a_obj // PERHAPS WHAT YOU WANT: copy all a's fields to b's fields.
                  // if you are relying sending a_obj's address somewhere in 
                  // APlease(), you may be out of luck.

  b_obj.field_unique_to_B = "initialized"
  return b_obj
}

Now that you can create B objects with fields initialized by APlease(), you can call A's methods on B's objects, and even call A's methods from within B like so:

func (B_obj *B) HelloB(){
  // can't call B_obj.HelloA() like you would expect
  B_obj.A.HelloA() // this works. Go "promotes" the anonymous field's methods 
                   // and fields to B_obj
                   // but they don't appear in B_obj, they appear in B_obj.A 
  fmt.Printf("And hello from B too; %s", B_obj.field_unique_to_B)
}

I will echo Rick-777 here and suggest you stick to go's naming conventions and idioms; NewReader is much easier to read and understand than ReaderPlease.

I contrived an example that I can put on bitbucket if people want. I think it's much easier to read when you are working with real metaphors; also a disclaimer - this is not the best code, but it does some things that answer your question.

file: car/car.go

package car

import "fmt"

type BaseCar struct {
    Doors  int // by default, 4 doors. SportsCar will have 2 doors
    Wheels int
}

func NewBaseCar() BaseCar {
    return BaseCar{Wheels: 4, Doors: 4}
}

// this will be used later to show that a "subclass" can call methods from self.BaseCar
func (c *BaseCar) String() string {
    return fmt.Sprintf("BaseCar: %d doors, %d wheels", c.Doors, c.Wheels)
}

// this will be promoted and not redefined
func (c *BaseCar) CountDoors() int {
    return c.Doors
}

file sportscar/sportscar.go

package sportscar

// You can think of SportsCar as a subclass of BaseCar. But go does
// not have conventional inheritence, and you can paint yourself into
// a corner if you try to force square c++ structures into round go holes.

import ( "../car" ; "fmt" )

type SportsCar struct {
    car.BaseCar // here is the anonymous field
    isTopDown   bool
}

func NewSportsCar() SportsCar {
    conv := SportsCar{} // conv.Wheels == 0

    conv.BaseCar = car.NewBaseCar() // now conv.Wheels == conv.Doors == 4

    conv.isTopDown = false // SportsCar-only field
    conv.Doors = 2         // Fewer Doors than BaseCar
    return conv
}

// SportsCar only method
func (s *SportsCar) ToggleTop() {
    s.isTopDown = !s.isTopDown
}

// "overloaded" string method note that to access the "base" String() method, 
// you need to do so through the anonymous field: s.BaseCar.String()
func (s *SportsCar) String() string {
    return fmt.Sprintf("Sports%s, topdown: %t", s.BaseCar.String(), s.isTopDown)
}

file main.go

package main

import ( "./car" ; "./sportscar" ; "fmt")

type Stringer interface { // added this complication to show
    String() string // that each car calls its own String() method
}

func main() {
    boring := car.NewBaseCar()
    fancy := sportscar.NewSportsCar()

    fmt.Printf("      %s\n", Stringer(&boring))
    fmt.Printf("%s\n", Stringer(&fancy))
    fancy.ToggleTop()
    fmt.Printf("%s\n", Stringer(&fancy))

    fmt.Println("BaseCar.CountDoors() method is callable from a SportsCar:", fancy.CountDoors())
}
于 2013-08-11T04:43:04.290 回答
-1

如果这是您正在寻找的,有一些方法可以在 Go 中模拟继承,请参阅本博客中的“继承”部分

于 2015-04-14T14:08:28.593 回答