第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

為什么 Go 在將指針作為值傳遞給函數(shù)時(shí)不報(bào)告編譯錯(cuò)誤?

為什么 Go 在將指針作為值傳遞給函數(shù)時(shí)不報(bào)告編譯錯(cuò)誤?

Go
哈士奇WWW 2023-07-31 16:54:54
我想如果我嘗試將指針傳遞給函數(shù),那么這個(gè)函數(shù)聲明也應(yīng)該接收一個(gè)指針?不確定,我嘗試過這個(gè):package mainimport (    "fmt")type I interface {    Get() int    Set(int)}type S struct {    Age int}func (s S) Get() int {    return s.Age}func (s *S) Set(age int) {    s.Age = age}func f(i I) {    i.Set(10)    fmt.Println(i.Get())}func main() {    s := S{}    f(&s) //4    fmt.Println(s.Get())}它打印1010我們看到 f 的函數(shù)是func f(i I)我不確定這是否是“按值傳遞”聲明,如果按值傳遞,則“i”不應(yīng)該在函數(shù)“f”之外更改,它是“f”內(nèi)部的副本。那么我到底錯(cuò)在哪一點(diǎn)呢?
查看完整描述

2 回答

?
蕪湖不蕪

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超7個(gè)贊

對(duì)于直接 C 代碼的相當(dāng)不完美的類比,想象一下:

var?x?interface{?...?}?//?fill?in?the?`...`?part?with?functions

或者在本例中,聲明i Imakei具有您定義的接口類型,就像聲明具有struct兩個(gè)成員的 C,一個(gè)用于保存類型,另一個(gè)用于保存該類型的值:

struct I {

? ? struct type_info *type;

? ? union {

? ? ? ? void *p;

? ? ? ? int i;

? ? ? ? double d;

? ? ? ? // add more types if/as needed here

? ? } u;

};

struct I i;

i.type當(dāng)您傳遞&sto時(shí),編譯器會(huì)填充槽i,并填充i.u.p為指向?qū)ο髎。1


當(dāng)您調(diào)用 時(shí)i.Set(10),Go 編譯器會(huì)將其轉(zhuǎn)換為等價(jià)的:


(*__lookup_func(i, "Set"))(i.u.p)

where__lookup_func找到實(shí)際的func (s *S) Set(age int)并且過多的魔法發(fā)現(xiàn)它應(yīng)該將指向s(from i.u.p) 的指針傳遞給該 setter 函數(shù)。2


事實(shí)上,某些接口類型的變量具有這兩個(gè)槽(“類型”部分和保存當(dāng)前值的類似聯(lián)合的部分),這是這里真正的秘密武器。您可以使用類型斷言:


v, ok := i.(int)

或類型開關(guān):


switch v := i.(type) {

case int: // code where `v` is `var v int`

case float64: // code where `v` is `var v float64` ...

// add more cases as desired

}

檢查類型槽,同時(shí)將值槽復(fù)制到新變量v。3


請(qǐng)注意,當(dāng)且僅當(dāng)兩個(gè)槽(和) 都為零時(shí)interface,變量才比較等于??偸亲屓死Щ蟮氖牵绻銖哪撤N非接口類型初始化一個(gè)值,它的槽就不再是 nil,并且測(cè)試:nil i.typei.uinterfacetype


if i == nil { // handle the case ...

不起作用,即使值槽(i.u.p在我們的類比中)是 nil。

我將其顯示為多個(gè) C 類型的聯(lián)合,但不包括struct類型。事實(shí)上,interface編譯器并沒有對(duì)值的第二個(gè)槽的大小做出任何承諾,盡管在當(dāng)前的編譯器中,它與任何其他指針一樣只有 8 個(gè)字節(jié)。但是,如果您擁有的任何值類型對(duì)于實(shí)際的底層實(shí)現(xiàn)來說太大,編譯器會(huì)插入一個(gè)分配:該值進(jìn)入一些額外的內(nèi)存,并且聯(lián)合的指針字段被設(shè)置為指向該值。

編譯器在編譯時(shí)檢查您填充到某個(gè)接口中的實(shí)際值的類型是否適合該接口。接口類型具有它必須支持的函數(shù)列表。如果底層類型具有這些函數(shù),則賦值就可以(并且編譯器知道構(gòu)建腳注 2 中提到的適當(dāng)?shù)念愃?vtable 的數(shù)據(jù))。如果基礎(chǔ)類型缺少某些函數(shù),您會(huì)收到編譯時(shí)錯(cuò)誤。因此,您絕對(duì)可以保證以后對(duì)接口變量的函數(shù)查找總是會(huì)成功。

2這里的查找比隱含的字符串查找更快,因?yàn)?code>Set編譯器在編譯時(shí)為該特定接口類型分配了一個(gè)整數(shù)代碼值,并且內(nèi)部struct type_info有各種快速查找表(有點(diǎn)類似于 C++ vtable)來幫助它以及。

在大多數(shù)情況下,“過多的魔法”大大減少為“將正確的參數(shù)放入正確的參數(shù)寄存器或堆棧位置”:復(fù)制被調(diào)用者從未讀取的額外字節(jié)是無害的。不過,如果整數(shù)與浮點(diǎn)需要不同的參數(shù)寄存器,那就有點(diǎn)棘手了,而且我不確定當(dāng)前的 Go 編譯器在這里實(shí)際上做了什么。

3在該v, ok := i.(int)表單中,如果類型槽包含int,v則設(shè)置為零,并且ok設(shè)置為false。無論實(shí)際類型如何,這都成立:所有類型都有默認(rèn)零值,并v成為您指定類型的零值。


查看完整回答
反對(duì) 回復(fù) 2023-07-31
?
慕村9548890

TA貢獻(xiàn)1884條經(jīng)驗(yàn) 獲得超4個(gè)贊

f(&s)正在按值傳遞指針地址s- 就像任何其他 go 函數(shù)調(diào)用一樣。該函數(shù)采用接口參數(shù)這一事實(shí)并沒有改變這一事實(shí)。

現(xiàn)在關(guān)于接口如何工作:接口值包含 2 項(xiàng):值和底層類型。本例中的值是指向該結(jié)構(gòu)的指針。該類型驗(yàn)證是否s滿足接口 - 因?yàn)樗鼘?shí)現(xiàn)了 Get/Set 函數(shù)簽名。

由于方法的指針接收器可以更改接收器的數(shù)據(jù)字段 -&s可以由該方法更改Set。通過擴(kuò)展,調(diào)用f(&s)(調(diào)用 Set)也會(huì)改變 structs的狀態(tài)。

PS 這種行為對(duì)于大多數(shù) go 標(biāo)準(zhǔn)庫來說至關(guān)重要。例如,許多包都http依賴于io.Reader&io.Writer接口。接受實(shí)現(xiàn)這些接口的值的函數(shù)和方法依賴于改變狀態(tài)、讀取網(wǎng)絡(luò)端口、刷新緩存等的底層具體類型來工作——同時(shí)不會(huì)給調(diào)用者帶來這些內(nèi)部副作用的負(fù)擔(dān)。


查看完整回答
反對(duì) 回復(fù) 2023-07-31
  • 2 回答
  • 0 關(guān)注
  • 148 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)