关于Golang代码片段 https://play.golang.org/p/PdJqR-pSN58 的几个问题

关于Golang代码片段 https://play.golang.org/p/PdJqR-pSN58 的几个问题 在…v, ok := m[“Barnabas”] fmt.Println(v) fmt.Println(ok) 这里的ok是什么意思?

另外,这里发生了什么:

if v, ok := m["Barnabas"]; ok {
    fmt.Println(v)
19 回复

但这有点偏离主题,所以我不会深入探讨

谢谢

更多关于关于Golang代码片段 https://play.golang.org/p/PdJqR-pSN58 的几个问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的。这是一个被选定的名称,不是保留字。

零值是什么意思?我知道它与布尔类型有关,但我对此不太理解

func main() {
    fmt.Println("hello world")
}

那么Go语言的规范就与计算机科学领域的通用术语存在分歧。

NobbZ:

不,并非如此,这被称为多值赋值。

谢谢

是的。这是一个选定的名称。不是保留字。 由编写程序的人选择的吗?(看我的理解有多基础?)

那么"ok"只是老师随意选择的一个变量名,还是它在Go语言中特指某个概念?

iegomez:

Go语言之旅

对这个有了初步理解

NobbZ:

那么 Go 语言的规范就与计算机科学领域的通用术语存在分歧。

其实不然。Go 语言支持元组赋值,只是没有元组类型。但这有点偏离主题,我就不深入探讨了。

ok 是一个变量。在 Go 语言中,函数可以返回任意数量的值。
在 if 语句中返回两个值,然后检查 ok 是否为 true。Go 允许在行内 if 语句中创建变量并检查其值...

jayts:

tuple assignment

不,这不是元组赋值,而是被称为多值赋值。

如果 Go 语言支持元组,我就可以这样写 t := 1, 2 并且将 t 作为包含两个值的变量来传递。

元组是一种结构体,其字段没有名称,而是通过索引/位置来标识。

jayts:

在 Go 语言中处理这种情况的方式是,访问映射时会返回两个值。第一个是元素(可能是之前存储的值,或者由于该位置没有存储任何内容而返回的零值),同时还会返回另一个值来指示属于这两种情况中的哪一种。

这一点对我来说非常清楚。

if v, ok := m["Barnabas"]; ok {
  // declare two new variables: v and ok
  // if ok variable is true; then the code here will be executed
  // so, it will print the v variable
  fmt.Println(v)
}

这被称为"逗号ok惯用法"。"ok"不是保留字,但在Go语言中被广泛使用。

例如,在检查映射值是否包含指定键时(就像你的示例中那样)。

这被称为"逗号ok惯用法"。"ok"不是保留字,但在Go语言中被广泛使用。

例如,在检查映射值是否包含指定键时(如你的示例所示)。

if v, ok := m["Barnabas"]; ok {
  // 声明两个新变量:v和ok
  // 如果ok变量为true,则此处的代码将被执行
  // 因此它将打印v变量
  fmt.Println(v)
}
if v, ok := m["Barnabas"]; ok {
  // 声明两个新变量:v和ok
  // 如果ok变量为true,则此处的代码将被执行
  // 因此它将打印v变量
  fmt.Println(v)
}

非常有帮助

元组赋值将多值操作的各个元素分配给变量列表。有两种形式。第一种形式中,右侧操作数是单个多值表达式,例如函数调用、通道映射操作,或类型断言。左侧操作数数量必须与值数量匹配。例如,若f是返回两个值的函数:

x, y = f()

将第一个值赋给x,第二个赋给y。第二种形式中,左侧操作数数量必须等于右侧表达式数量,每个表达式必须是单值,右侧第n个表达式赋给左侧第n个操作数:

one, two, three = '一', '二', '三'

哦,好的。这很清晰。

对于第一个示例,来自 Go 语言之旅(这里是相关章节):

elem, ok = m[key]

如果 key 存在于 m 中,oktrue。如果不存在,okfalse。 如果 key 不在映射中,那么 elem 是该映射元素类型的零值。

简而言之,ok(或者你给访问映射时返回的第二个值起的任何名称,它是一个 bool 类型)会告诉你该键是否存在。

在第二个示例中,Go 语言中的 if 可以在条件检查之前以一个简短语句开始。这几乎等同于以下写法:

v, ok := m[“Barnabas”]
if ok {
  fmt.Println(v)
}

我说几乎是因为在后一种情况下,ok 位于其所在函数的局部作用域内,而在你的示例中(当语句是 if 的一部分时),ok 位于 if 的局部作用域内,也就是说,它不能在 if 之后使用。请参考我之前提到过这一点的帖子。同样,Go 语言之旅也提到了这一点:https://tour.golang.org/flowcontrol/6

你好 Norbert,

我直接使用了《Go 编程语言规范》中的术语。元组赋值这一术语在赋值章节中有详细说明:

图片 go.dev

图片

Go 编程语言规范 - Go 编程语言

为了节省你的时间,我将第三个浅灰色框之后的内容放在这里:

元组赋值将多值操作中的各个元素分配给一个变量列表。它有两种形式。第一种形式中,右侧操作数是单个多值表达式,例如函数调用、通道映射操作,或类型断言。左侧的操作数数量必须与值的数量匹配。例如,如果 f 是返回两个值的函数:

x, y = f()

将第一个值赋给 x,第二个值赋给 y。第二种形式中,左侧的操作数数量必须等于右侧的表达式数量,每个表达式必须是单值的,并且右侧的第 n 个表达式赋给左侧的第 n 个操作数:

one, two, three = '一', '二', '三'

在Go语言中,当从map中通过键获取值时,可以返回两个值:第一个是键对应的值(如果键不存在则返回该值类型的零值),第二个是一个布尔值,表示该键是否存在于map中。

在你的代码片段中:

v, ok := m["Barnabas"]
fmt.Println(v)
fmt.Println(ok)

这里的ok是一个布尔变量,如果map m中存在键"Barnabas",则ok的值为true,否则为false

对于第二个代码片段:

if v, ok := m["Barnabas"]; ok {
    fmt.Println(v)
}

这是一个if语句的初始化语句用法。这里发生了以下操作:

  1. 执行初始化语句:v, ok := m["Barnabas"],从map中获取值并检查键是否存在
  2. 条件判断:ok(如果为true则执行if块内的代码)
  3. 只有当键"Barnabas"存在于map中时,才会打印对应的值v

这种写法是Go语言中检查map中键是否存在并安全访问值的常用模式。如果键不存在,okfalse,if块内的代码不会执行,避免了访问不存在的键导致的意外行为。

示例:

m := map[string]int{
    "Alice": 25,
    "Bob": 30,
}

// 键存在的情况
if v, ok := m["Alice"]; ok {
    fmt.Println(v) // 输出: 25
}

// 键不存在的情况
if v, ok := m["Barnabas"]; ok {
    fmt.Println(v) // 这行不会执行
}
回到顶部