![](/img/trans.png)
[英]How can I create a method that gets called every time a public method gets called?
[英]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.