2011-06-26 26 views
3

如果類型T1T2基於T類型和類型T只開始存在從NewT1()NewT2(),有沒有什麼辦法的功能func (*T) WhoAmI()可以知道它是否「真的」是一個T1T2在Go中,一種類型被強制轉換爲另一種類型,可以通過一種方法來確定接收器的類型?

 
package main 
import "fmt" 
import "reflect" 

type T struct { s string } 
func (v *T) WhoAmI() string { 

     // pull type name with reflect 
     fmt.Println(reflect.TypeOf(v).Elem().Name()) // always prints "T"! 

     // todo: if I am actually T1 
     return "T1" 
     // todo: else if I am actually T2 
     return "T2" 
} 

type T1 T 
func NewT1(s string) T1 { return T1{ s } } 

type T2 T 
func NewT2(s string) T2 { return T2{ s } } 

func main() { 
     var t1 = T1{ "xyz" } 
     var t2 = T2{ "pdq" } 
     s1 := ((*T)(&t1)).WhoAmI()  // would like to return "T1" 
     s2 := ((*T)(&t2)).WhoAmI()  // would like to return "T2" 
     fmt.Println(s1, s2) 
} 

從技術上說:

一次t1T1被強迫T所以func (*T) WhoAmI()可以稱爲類型,並t1完全失去的事實,它的類型是真的T1?如果不是,我們如何從接收類型T的方法的角度回收知識?

一般說:如果一種類型是基於另一

換句話說

,如果派生類型的變量被強制到基本類型來運行的方法,可以在方法學的實數型的接聽者是誰?

+0

我剛想過'reflect.TypeOf'。不幸的是,該函數將返回您輸入的類型。你確定要演員嗎?如果你使用的是接口,你根本不需要施放。 – Kissaki

+0

如果類型字段不同並且無法投射,鑄造將會失敗!然後你可以嘗試一個演員,並抓住不可能的情況,從而知道它是哪種類型。在沒有不同字段或方法的情況下進行簡單的嘗試,但這並不奏效,因爲投射顯然有效。 – Kissaki

+0

想那樣。你能說出'int(some_float)'是什麼類型嗎? –

回答

4

不,這是不可能的。從舊的創建一個新的類型不像創建一個新的類繼承自一個基於類的語言的父類。在你的情況下,T對T1或T2都一無所知,如果你正在調用WhoAmI方法,你有一個定義類型T的接收器。

您的設計在界面上可能會更好。嘗試更多的東西是這樣的:

type T interface { 
    WhoAmI() string 
} 

type T1 struct { 
    s string 
} 

func (t *T1) WhoAmI() string { return "T1" } 

type T2 struct { 
    s string 
} 

func (t *T2) WhoAmI() string { return "T2" } 

嘗試它的Go playground

T1和T2都實現了接口T,所以它們可以作爲類型T

+0

謝謝!通過接口,每種類型都必須實現接口的所有方法,這是我試圖解決的問題 –

2

埃文的回答是不錯的。但是,有多種方法可以解決這個問題,它們更接近您正在尋找的問題。

當你轉換,你實際上改變類型,沒有什麼殘餘。去只關心什麼類型是目前的類型。

解決這個問題的一種方法就是編寫一個函數。函數對共享實現非常有用。一些面向對象的語言將它們拋出爲不純,但他們不知道它們錯過了什麼(我在看你public static void!)。

func WhoAmI(v interface{}) string { 
    switch v.(type) { 
    case *T: return "*T" 
    case *T1: return "*T1" 
    case *T2: return "*T2" 
    } 

    return "unknown" 
} 

現在,您不必爲了調用方法/函數而轉換該值。當然,如果你打算做一個類型切換併爲每種類型做一些不同的事情,那麼你可以爲每種類型寫一個不同的方法。

要使它成爲一個方法,你可以這樣做:

type T struct { s string } 
func (t *T) WhoAmI() string { return WhoAmI(t) } 

type T1 T 
func (t1 *T1) WhoAmI() string { return WhoAmI(t1) } 

這樣,你不需要重新實現方法。

如果你真的想要T知道自己,給它一個自我!有兩種方法可以做到這一點。一個是作爲參數:

func (t *T) WhoAmI(self interface{}) string { ... } 
... 
fmt.Println(t.WhoAmI(t)) 
fmt.Println(((*T)(t1)).WhoAmI(t1)) 

這個好處是你不需要做任何額外的工作。該方法可以訪問t和self,所以它具有兩全其美的優點。但是,這成爲您的界面的一部分,這是有點尷尬。

你也可以讓它變成一個領域:

type T struct { self interface{} } 
func NewT() *T { 
    t := new(T) 
    t.self = t 
    return t 
} 

type T1 T 
func NewT1() *T1 { 
    t1 := new(T1) 
    t1.self = t1 
    return t1 
} 

現在,在TT1任何方法可以告訴對象最初是通過檢查self創建。

可以保持來回轉換得到的方法,或者你可以使用一個功能叫做嵌入:

type T struct{} 
func (t *T) M() {} 

type T1 struct { T } 
... 
var t T 
var t1 T1 
t.M() 
t1.M() 

正如你所看到的,你可以通過tt1T.M。但是,請記住T.M總是隻會看到一個T,無論您打電話給誰(tt1)。您必須使用上述策略之一才能使T.M能夠看到T1

相關問題