5 回答
TA貢獻(xiàn)1863條經(jīng)驗(yàn) 獲得超2個(gè)贊
為了詳細(xì)說明我的評(píng)論,Effective Go提到訪問映射鍵的多值分配稱為“逗號(hào)確定”模式。
有時(shí)您需要將缺失的條目與零值區(qū)分開來。是否有“UTC”條目,或者是空字符串,因?yàn)樗静辉诘貓D中?你可以用多重賦值的形式來區(qū)分。
var seconds int
var ok bool
seconds, ok = timeZone[tz]
出于顯而易見的原因,這被稱為“逗號(hào)確定”習(xí)語(yǔ)。在這個(gè)例子中,如果 tz 存在,秒將被適當(dāng)?shù)卦O(shè)置并且 ok 為真;如果沒有,秒將被設(shè)置為零,確定將是假的。
操場(chǎng)證明這個(gè)
我們可以看到這與調(diào)用常規(guī)函數(shù)不同,在常規(guī)函數(shù)中編譯器會(huì)告訴您出現(xiàn)問題:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
在操場(chǎng)上,這將輸出
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
這給了我們一個(gè)提示,它可能是編譯器正在做的事情。搜索“commaOk”的源代碼為我們提供了幾個(gè)可以查看的地方,包括types.unpack
在撰寫本文時(shí),該方法的 godoc 內(nèi)容如下:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
其關(guān)鍵在于此方法似乎可以確定某事是否實(shí)際上是“逗號(hào)正?!鼻闆r。
挖掘到這個(gè)方法告訴我們,它會(huì)檢查,看是否操作數(shù)的模式索引地圖或者模式設(shè)置為commaok(其中這個(gè)定義確實(shí)給我們當(dāng)?shù)挠盟谠S多提示,但搜索任務(wù)源到commaok我們可以看到它時(shí)所使用的正從一個(gè)信道的值和類型的斷言)。記住加粗的部分以備后用!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk是函數(shù)的參數(shù)。查看unpack在該文件中調(diào)用的位置,我們可以看到所有調(diào)用者都false作為參數(shù)傳遞。搜索庫(kù)的其余部分使我們assignments.go的Checker.initVars()方法。
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
由于在執(zhí)行多值賦值時(shí)我們似乎只能使用“逗號(hào)確定”模式來獲取兩個(gè)返回值,因此這似乎是正確的地方!在上面的代碼中,檢查了左邊的長(zhǎng)度,當(dāng)unpack被調(diào)用時(shí),allowCommaOk參數(shù)是l == 2 && !returnPos.IsValid(). 將!returnPos.IsValid()在一定程度上混淆這里作為這將意味著,位置沒有相關(guān)的文件或行信息與它,但我們會(huì)就忽略這個(gè)問題。
在該方法中,我們有:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
那么這一切告訴我們什么呢?
由于該unpack方法allowCommaOk在除inassignment.go的Checker.initVars()方法之外的任何地方都采用硬編碼為 false的參數(shù),我們可以假設(shè)您在進(jìn)行賦值時(shí)只會(huì)得到兩個(gè)值,并且在左側(cè)有兩個(gè)變量。
該unpack方法將通過檢查您是否正在索引切片、從通道中獲取值或進(jìn)行類型斷言來確定您是否確實(shí)獲得了ok返回值
由于您只能ok在進(jìn)行賦值時(shí)獲取值,因此在您的特定情況下,您將始終需要使用變量
TA貢獻(xiàn)1825條經(jīng)驗(yàn) 獲得超6個(gè)贊
您可以使用命名返回來保存幾個(gè)擊鍵:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
但除此之外,我不認(rèn)為你想要的是可能的。
TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超10個(gè)贊
簡(jiǎn)單地說:你的第二個(gè)例子不是有效的 Go 代碼的原因是因?yàn)檎Z(yǔ)言規(guī)范是這樣說的。;)
索引映射只會(huì)在兩個(gè)變量的賦值中產(chǎn)生一個(gè)次要值。Return 語(yǔ)句不是賦值語(yǔ)句。
在特殊形式的賦值或初始化中使用的類型為 map[K]V 的映射 a 上的索引表達(dá)式
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]產(chǎn)生一個(gè)額外的無類型布爾值。如果鍵 x 存在于映射中,則 ok 的值為真,否則為假。
此外,索引映射不是“對(duì)多值函數(shù)的單一調(diào)用”,它是從函數(shù)返回值的三種方法之一(第二種方法,其他兩種在這里不相關(guān)):
有三種方法可以從具有結(jié)果類型的函數(shù)返回值:
返回值可以在“return”語(yǔ)句中明確列出。每個(gè)表達(dá)式必須是單值的并且可以分配給函數(shù)結(jié)果類型的相應(yīng)元素。
“return”語(yǔ)句中的表達(dá)式列表可能是對(duì)多值函數(shù)的單個(gè)調(diào)用。效果就好像從該函數(shù)返回的每個(gè)值都被分配給一個(gè)具有相應(yīng)值類型的臨時(shí)變量,然后是一個(gè)列出這些變量的“返回”語(yǔ)句,此時(shí)適用前一種情況的規(guī)則。
如果函數(shù)的結(jié)果類型為其結(jié)果參數(shù)指定名稱,則表達(dá)式列表可能為空。結(jié)果參數(shù)作為普通的局部變量,函數(shù)可以根據(jù)需要為它們賦值。“return”語(yǔ)句返回這些變量的值。
至于您的實(shí)際問題:避免臨時(shí)變量的唯一方法是使用非臨時(shí)變量,但這通常是非常不明智的 - 即使在安全的情況下也可能沒有太多優(yōu)化。
那么,為什么語(yǔ)言規(guī)范不允許在 return 語(yǔ)句中使用這種特殊的映射索引(或類型斷言或通道接收,兩者都可以使用“逗號(hào)確定”習(xí)語(yǔ))?這是個(gè)好問題。我的猜測(cè):保持語(yǔ)言規(guī)范簡(jiǎn)單。
- 5 回答
- 0 關(guān)注
- 521 瀏覽
添加回答
舉報(bào)
