Go语言错误总结(二)

本文深入探讨了Go语言中常见的编程误区,包括nil的Slices和Maps处理、Map的容量使用、字符串nil分配、Array函数参数误解、Slice和Array的range使用、多维Array和Slice的特性、MapKeys访问及检测等关键点,为Go语言开发者提供了宝贵的实践指导。
摘要由CSDN通过智能技术生成

8、使用“nil” Slices and Maps

在一个nil的slice中添加元素是没问题的,但对一个map做同样的事将会生成一个运行时的panic。

正确代码:

package main
func main() {    var s []int    s = append(s, 1)}

错误代码:

​​​​​​​

package main
func main() {    var m map[string]int    m["one"] = 1}

运行错误:

panic: assignment to entry in nil map

9、Map的容量

你可以在map创建时指定它的容量,但你无法在map上使用cap()函数。

错误代码:

 

package main
func main() {    m := make(map[string]int, 99)    cap(m)}

编译错误:

 

./main.go:5:5: invalid argument m (type map[string]int) for cap

10、字符串不会为nil

这对于经常使用nil分配字符串变量的开发者而言是个需要注意的地方。

​​​​​​​

package main
func main() {    var x string = nil    if x == nil {        x = "default"    }}

编译错误:

​​​​​​​

./main.go:4:6: cannot use nil as type string in assignment./main.go:5:7: invalid operation: x == nil (mismatched types string and nil)

正确代码:

​​​​​​​

package main
func main() {    var x string    if x == "" {        x = "default"    }}

11、Array函数的参数

如果你是一个C或则C++开发者,那么数组对你而言就是指针。当你向函数中传递数组时,函数会参照相同的内存区域,这样它们就可以修改原始的数据。Go中的数组是数值,因此当你向函数中传递数组时,函数会得到原始数组数据的一份复制。如果你打算更新数组的数据,这将会是个问题。​​​​​​​

package main
import "fmt"
func main() {    x := [3]int{1, 2, 3}    func(arr [3]int) {        arr[0] = 7        fmt.Println(arr) //prints [7 2 3]    }(x)    fmt.Println(x) //prints [1 2 3] (not ok if you need [7 2 3])}

运行结果:

​​​​​​​

[7 2 3][1 2 3]

如果你需要更新原始数组的数据,你可以使用数组指针类型。

package main

import "fmt"
func main() {    x := [3]int{1, 2, 3}    func(arr *[3]int) {        (*arr)[0] = 7        fmt.Println(arr) //prints &[7 2 3]    }(&x)    fmt.Println(x) //prints [7 2 3]}

运行结果:

&[7 2 3][7 2 3]

另一个选择是使用slice。即使你的函数得到了slice变量的一份拷贝,它依旧会参照原始的数据。

package main
import "fmt"
func main() {    x := []int{1, 2, 3}    func(arr []int) {        arr[0] = 7        fmt.Println(arr) //prints [7 2 3]    }(x)    fmt.Println(x) //prints [7 2 3]}

运行结果:​​​​​​​

[7 2 3][7 2 3]

12、在Slice和Array使用“range”语句时的出现的不希望得到的值

如果你在其他的语言中使用“for-in”或者“foreach”语句时会发生这种情况。Go中的“range”语法不太一样。它会得到两个值:第一个值是元素的索引,而另一个值是元素的数据。

package main

import "fmt"
func main() {    x := []string{"a", "b", "c"}    for v := range x {        fmt.Println(v) //prints 0, 1, 2    }}

运行结果:​​​​​​​

012
package main
import "fmt"
func main() {    x := []string{"a", "b", "c"}    for _, v := range x {        fmt.Println(v) //prints a, b, c    }}

运行结果:​​​​​​​

abc

13、Slices和Arrays是一维的

看起来Go好像支持多维的Array和Slice,但不是这样的。尽管可以创建数组的数组或者切片的切片。对于依赖于动态多维数组的数值计算应用而言,Go在性能和复杂度上还相距甚远。

你可以使用纯一维数组、“独立”切片的切片,“共享数据”切片的切片来构建动态的多维数组。

如果你使用纯一维的数组,你需要处理索引、边界检查、当数组需要变大时的内存重新分配。使用“独立”slice来创建一个动态的多维数组需要两步。首先,你需要创建一个外部的slice。然后,你需要分配每个内部的slice。内部的slice相互之间独立。你可以增加减少它们,而不会影响其他内部的slice。

package main
func main() {    x := 2    y := 4    table := make([][]int, x)    for i := range table {        table[i] = make([]int, y)    }}

使用“共享数据”slice的slice来创建一个动态的多维数组需要三步。首先,你需要创建一个用于存放原始数据的数据“容器”。然后,你再创建外部的slice。最后,通过重新切片原始数据slice来初始化各个内部的slice。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
package main
import "fmt"
func main() {    h, w := 2, 4    raw := make([]int, h*w)    for i := range raw {        raw[i] = i    }    fmt.Println(raw, &raw[4])    //prints: [0 1 2 3 4 5 6 7] <ptr_addr_x>    table := make([][]int, h)    for i := range table {        table[i] = raw[i*w : i*w+w]    }    fmt.Println(table, &table[1][0])    //prints: [[0 1 2 3] [4 5 6 7]] <ptr_addr_x>}

运行结果:

 
[0 1 2 3 4 5 6 7] 0xc4200140a0[[0 1 2 3] [4 5 6 7]] 0xc4200140a0

关于多维array和slice已经有了专门申请,但现在看起来这是个低优先级的特性。

14、访问不存在的 Map Keys

这对于那些希望得到“nil”标示符的开发者而言是个技巧(和其他语言中做的一样)。如果对应的数据类型的“零值”是“nil”,那返回的值将会是“nil”,但对于其他的数据类型是不一样的。检测对应的“零值”可以用于确定map中的记录是否存在,但这并不总是可信(比如,如果在二值的map中“零值”是false,这时你要怎么做)。检测给定map中的记录是否存在的最可信的方法是,通过map的访问操作,检查第二个返回的值。

package main
import "fmt"
func main() {    x := map[string]string{"one": "a", "two": "", "three": "c"}    if v := x["two"]; v == "" {        fmt.Println("no entry")    }}运行结果:
 
no entry
 
package main
import "fmt"
func main() {    x := map[string]string{"one": "a", "two": "", "three": "c"}    if _, ok := x["two"]; !ok {        fmt.Println("no entry")    } else {        fmt.Println("exist")    }}

运行结果:

exist
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值