为什么 map 和类型断言可以返回 1 或 2 个值?

huangapple go评论72阅读模式
英文:

Why map and type assertion can return 1 or 2 values?

问题

定义一个映射(map)时,我们可以这样做:

value, present := m["key"]

或者:

value := m["key"]

通过类型断言,我们可以这样做:

var i interface{} = "hello"

s := i.(string)
fmt.Println(s)

s, ok := i.(string)
fmt.Println(s, ok)

但是我找不到一种定义一个函数可以返回一个值或两个值的方法。

例如:

func hello() (string, error) {
    return "world", nil
}

当我调用这个函数时,我得到:

v, ok := hello() // 有效
v := hello() // 无效

PS:我知道类似template.Must的用法,但它似乎不同。我真的想知道映射和类型断言是如何实现的,这样我就可以将其应用到函数中。

提前感谢你的帮助。(我表达清楚了吗?我英文不好,抱歉)。

英文:

To define a map, we can do such a thing:

value, present := m["key"]

or:

value := m["key"]

and with type assertion, we can do:

var i interface{} = "hello"

s := i.(string)
fmt.Println(s)

s, ok := i.(string)
fmt.Println(s, ok)

but I can't find a way to define a func that can return 1 value or 2-values.

For instance:

func hello() (string, error) {
    return "world", nil
}

When I invoke this func I get:

v, ok := hello() // valid
v := hello() // invalid

PS: I know how something like template.Must works, but it seems different. I really want to know how Map and type assertion can do the magic, so I can apply it to functions.

Thanks in advance. (Am I clear? I have poor English sorry).

答案1

得分: 7

《Go编程语言规范》

函数类型

函数类型表示具有相同参数和结果类型的所有函数的集合。

FunctionType   = "func" Signature .
Signature      = Parameters [ Result ] .
Result         = Parameters | Type .
Parameters     = "(" [ ParameterList [ "," ] ] ")" .
ParameterList  = ParameterDecl { "," ParameterDecl } .
ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

空白标识符

空白标识符用下划线字符 _ 表示。

赋值

空白标识符提供了一种忽略赋值语句中右侧值的方式:

x, _ = f()  // 调用 f(),但忽略第二个结果值

映射、类型断言和带有 range 子句的 for 语句是 Go 编程语言的特殊功能。对于普通函数类型,无法具有可变数量的返回值。

您可以使用下划线(_)或空白标识符来忽略返回值,也可以使用包装函数。例如:

package main

import "fmt"

func two() (int, bool) {
    return 42, true
}

func one() int {
    r, _ := two()
    return r
}

func main() {
    r, ok := two()
    r, _ = two()
    r = one()
    fmt.Println(r, ok)
}
英文:

> The Go Programming Language Specification
>
> Function types
>
> A function type denotes the set of all functions with the same
> parameter and result types.
>
> FunctionType = "func" Signature .
> Signature = Parameters [ Result ] .
> Result = Parameters | Type .
> Parameters = "(" [ ParameterList [ "," ] ] ")" .
> ParameterList = ParameterDecl { "," ParameterDecl } .
> ParameterDecl = [ IdentifierList ] [ "..." ] Type .
>
> Blank identifier
>
> The blank identifier is represented by the underscore character _.
>
> Assignments
>
> The blank identifier provides a way to ignore right-hand side values
> in an assignment:
>
> x, _ = f() // evaluate f() but ignore second result value

Maps, type assertions, and the for statement with a range clause are special features of the Go programming language. You can't have a variable number of return values for an ordinary function type.

You can ignore a return value with an underscore (_), the blank identifier, or you can use a wrapper function. For example,

package main

import "fmt"

func two() (int, bool) {
	return 42, true
}

func one() int {
	r, _ := two()
	return r
}

func main() {
	r, ok := two()
	r, _ = two()
	r = one()
	fmt.Println(r, ok)
}

答案2

得分: 6

地图和类型断言可以做到这一点,因为它们不是函数,而是语言的结构。该行为在规范中有描述:

对于类型为 map[K]V 的地图 a,在赋值或初始化的特殊形式中使用的索引表达式

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]

会产生一个额外的无类型布尔值。如果键 x 存在于地图中,则 ok 的值为 true,否则为 false。

而对于在赋值或初始化的特殊形式中使用的类型断言

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)

也会产生一个额外的无类型布尔值。如果断言成立,则 ok 的值为 true。否则,ok 的值为 false,v 的值为类型 T 的零值。在这种情况下不会发生运行时恐慌。

这不是通用函数可以做到的事情,因此需要使用 Must 模式来显式地重现相同的行为。

英文:

Map and type assertions can do this because they are not functions, but structures of the language. The behavior is described in the spec

> An index expression on a map a of type map[K]V used in an assignment
> or initialization of the special form
>
> v, ok = a[x]
> v, ok := a[x]
> var v, ok = a[x]
>
> yields an additional untyped boolean value. The value of ok is true if
> the key x is present in the map, and false otherwise.

and

> A type assertion used in an assignment or initialization of the
> special form
>
> v, ok = x.(T)
> v, ok := x.(T)
> var v, ok = x.(T)
>
> yields an additional untyped boolean value. The value of ok is true if
> the assertion holds. Otherwise it is false and the value of v is the
> zero value for type T. No run-time panic occurs in this case.

It is not something that can be done on general functions, hence the Must pattern that explicitely reproduce the same behavior.

huangapple
  • 本文由 发表于 2016年3月27日 14:59:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/36244725.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定