簡體   English   中英

如何在golang中創建自動調用的結構方法?

[英]How to create a method of a structure in golang that is called automatically?

我必須在golang中創建一個類似於2級繼承的替代項,即在一個包中,我有一個structure( A ),它由另一個包中的另一個structure( B )繼承(嵌入為匿名字段) ,其對象將由“ 主要 ”包使用。

現在,我為“ B”( BPlease )創建了一個初始化器方法,該方法返回B的對象(例如B_obj )。 我可以在程序開始時從我的“ main”包中調用此初始化程序( BPlease )。

之一的“B”的方法(比如,HelloB()),在執行期間調用“A”(比如說,HelloA())的方法,使用“B的”對象。

但是我真正想要的是,類似“ A”的構造函數,它可以在“ B”調用任何“ A”方法之前初始化其字段(最好是在“ main”包中創建B_obj時)。

如何實現呢?

我也嘗試為“ A”創建一個初始化器( APlease ),並調用它( BPlease )以獲取“ A”的對象(A_obj)。 但是我發現此對象無用,因為我無法利用它在“ B”(HelloB())方法內部調用“ A's”方法(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,而且,某些字段值是通過調用具有相同結構的方法生成的。

不管任何人反對在不存在的情況下與該語言爭奪繼承權的觀點:不,沒有魔術方法,例如“ getter”或“ setter”之類的方法。 遠程關聯(魔術)可能是終結器,但在這種情況下,它們肯定不會有所幫助。

但是,我建議停止在Go中編碼X語言。 只需使用Go。 Go不使用“類式”繼承,Go程序員(通常)也不應該使用。 將Go視為現代化的C。沒有太多的C代碼依賴於繼承。 (好的,我知道GObject ;-)

一些元注釋:“第一結構”和“第二結構”使得很難理解哪個是哪個。 標記諸如A,B和C之類的不同事物是使數學如此強大的工具。

這是您的問題嗎:您有兩個類型A和B,B嵌入A。您要確保B在“意義上也被完全初始化”的情況下也被初始化。

原始草圖:

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。

要稍微擴展一下Volker的答案,您應該可以致電

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
}

現在您可以使用由APlease()初始化的字段創建B對象,您可以在B的對象上調用A的方法,甚至可以從B內部調用A的方法,如下所示:

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)
}

我會在這里回應Rick-777,建議您堅持使用命名約定和習慣用語。 NewReader比ReaderPlease更容易閱讀和理解。

我構想出一個示例,如果人們願意,我可以將其放置在bitbucket上。 我認為在使用真正的隱喻時,閱讀起來容易得多。 也是免責聲明-這不是最好的代碼,但是它確實可以回答您的問題。

檔案: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
}

文件sportcar / 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)
}

文件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())
}

如果您要尋找的是Go中有多種模仿繼承的方法,請參閱此博客中的 “繼承”部分

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM