Mistakes of Golang
记录个人在学习和编写go项目/习题时出现的错误
1.字符转换string to int
int(a[index])
这样的转换得到的是字符的 ASCII 码值,而不是二进制数 0
或 1
。正确的做法是将字符减去字符 '0'
来得到对应的整数值。
//错误案例
int_a = int(str_a[index])
//正确做法
int_a = int(str_a[index] - '0')
2.字符串拼接错误
string(value%2)
这样的转换会把 value%2
的整数值当作 Unicode 码点来转换为字符串,而不是得到 '0'
或 '1'
字符。应该使用 strconv.Itoa(value%2)
或者直接通过 value%2 + '0'
来得到字符。
values := []int{0, 1}
for _, value := range values {
// 通过 value % 2 + '0' 得到字符
char := value%2 + '0'
str := string(char)
fmt.Printf("值 %d 转换后的字符串是: %s\n", value, str)
}
3.Map的取用
当从一个 map 中取值时,还有可以选择是否接收的第二个返回值,该值表明了 map 中是否存在这个键。 这可以用来消除 键不存在
和 键的值为零值
产生的歧义, 例如 0
和 MARKDOWN_HASH6bff6326b614b5f92cd2dac85b7a4e01MARKDOWNHASH
。这里我们不需要值,所以用 空白标识符(blank identifier) 将其忽略。
if k, exists := hashTable[complement]; exists {
}
//if k, exists := hashTable[complement]; exists:检查互补数是否已经存在于哈希表中。如果存在,k 会被赋值为互补数对应的索引,exists 为 true
错误用法,
if k,v := hashTable[target-num]; v {
return []int{v, index}
}
把key,value = hashTable[key],当成取用key和calue值。这太滑稽了
4.for range循环创建的是元素副本
func main() {
slice := []int{0,1,2,3}
m := make(map[int]*int)
for key,val := range slice {
m[key] = &val
}
for k,v := range m {
fmt.Println(k,"->",*v)
}
}
输出:
0 -> 3
1 -> 3
2 -> 3
3 -> 3
参考解析:
for
循环变量的作用域:
在 Go 语言的for
循环里,val
是一个迭代变量,它在整个for
循环的生命周期内都存在,并且每次迭代时都会被重新赋值。也就是说,在每次循环中,val
都会被赋予切片中当前元素的值,但它的内存地址始终保持不变。- 将
val
的地址存入map
:
在循环中,m[key] = &val
这行代码将val
的内存地址存入了map
中。由于每次迭代时val
的内存地址都不变,所以map
中所有键对应的值都是同一个内存地址。 - 循环结束后
val
的值:
当循环结束时,val
的值是切片的最后一个元素的值,也就是3
。因此,当你遍历map
并通过指针解引用获取值时,所有的值都是3
。
示例说明
假设 val
的内存地址是 0x123456
,在第一次迭代时,val
的值是 0
,map
中 0
这个键对应的值是 0x123456
;
在第二次迭代时,val
的值变成了 1
,但内存地址还是 0x123456
,map
中 1
这个键对应的值同样是 0x123456
;
以此类推,直到循环结束,val
的值是 3
,map
中所有键对应的值都是指向存储 3
的内存地址 0x123456
。
正确的写法:
要在每次迭代时创建一个新的变量来存储当前元素的值,然后将这个新变量的地址存入 map
func main() {
slice := []int{0,1,2,3}
m := make(map[int]*int)
for key,val := range slice {
value := val
m[key] = &value
}
for k,v := range m {
fmt.Println(k,"===>",*v)
}
}