亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么 golang 禁止賦值給相同的底層類型,當一個是本機類型時?

為什么 golang 禁止賦值給相同的底層類型,當一個是本機類型時?

Go
蠱毒傳說 2021-09-13 19:52:38
考慮這個代碼:package mainimport "fmt"type specialString stringfunc printString(s string) {    fmt.Println(s)}// unlike, say, C++, this is not legal GO, because it redeclares printString//func printString(s specialString) {    //  fmt.Println("Special: " + s)//}func main() {    ss := specialString("cheese")    // ... so then why shouldn't this be allowed?    printString(ss)}我的問題是:為什么語言被定義為不允許調用printString(ss)in main()?(我不是在尋找指向 Golang 賦值規則的答案;我已經閱讀了它們,并且我看到 specialString 和 string 都具有相同的“底層類型”并且兩種類型都是“命名的”——如果你考慮要命名的泛型類型“字符串”,Golang 顯然是這樣做的——因此它們在規則下不可分配。)但是為什么會有這樣的規則呢?通過將內置類型視為“命名”類型并阻止您將命名類型傳遞給所有接受相同底層內置類型的標準庫函數,解決了什么問題?有人知道這里的語言設計者是怎么想的嗎?從我的角度來看,它似乎在代碼中創建了很多毫無意義的類型轉換,并且不鼓勵在真正有意義的地方使用強類型。
查看完整描述

2 回答

?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

我相信這里最初作者的邏輯是命名類型的命名是有原因的 - 它代表不同的東西,而不僅僅是底層類型。


我想我在 golang-nuts 的某個地方讀過它,但不記得確切的討論。


考慮以下示例:


type Email string

您將其命名為 Email,因為您需要表示電子郵件實體,而 'string' 只是它的簡化表示,足夠一開始。但稍后,您可能希望將 Email 更改為更復雜的內容,例如:


type Email struct {

    Address string

    Name    string

    Surname string

}

假設它是一個字符串,這將破壞所有與 Email 一起使用的代碼。


查看完整回答
反對 回復 2021-09-13
?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

這是因為 Go 沒有類繼承。它使用結構組合代替。命名類型不會從它們的底層類型繼承屬性(這就是為什么它不被稱為“基本類型”)。


因此,當您specialString使用預定義類型的基礎類型聲明命名類型時string,您的新類型與基礎類型完全不同。這是因為 Go 假設您希望為新類型分配不同的行為,并且在運行時之前不會檢查其基礎類型。這就是 Go 既是靜態語言又是動態語言的原因。


當你打印


fmt.Println(reflect.TypeOf(ss))        // specialString

你得到specialString,不是string。如果你看一下Println()定義如下:


func Println(a ...interface{}) (n int, err error) {

        return Fprintln(os.Stdout, a...)

}

這意味著您可以打印任何預先聲明的類型(int、float64、string),因為它們都實現了至少零個方法,這使得它們已經符合空接口并作為“可打印”傳遞,但不是您的命名類型specialString,它仍然未知在編譯期間去。我們可以通過打印 our interface{}against的類型來檢查specialString。


type specialString string 

type anything interface{}


s := string("cheese")

ss := specialString("special cheese")

at := anything("any cheese")


fmt.Println(reflect.TypeOf(ss))     // specialString

fmt.Println(reflect.TypeOf(s))      // string

fmt.Println(reflect.TypeOf(at))     // Wow, this is also string!

你可以看到它specialString一直在調皮它的身份?,F在,看看它在運行時傳遞給函數時的效果


func printAnything(i interface{}) {

        fmt.Println(i)

}


fmt.Println(ss.(interface{}))       // Compile error! ss isn't interface{} but

printAnything(ss)                   // prints "special cheese" alright

ss就interface{}功能而言已經過得去。到那時,Go 已經創建了ss一個interface{}.


查看完整回答
反對 回復 2021-09-13
  • 2 回答
  • 0 關注
  • 216 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號