前言
新的一年,好好学习。
正文
问题来源
本问题来自Go Gotchas。
1.直接给空的map赋值
错误代码
var m map[string]float64
m["pi"] = 3.1416
执行结果
panic: assignment to entry in nil map
解答
需要提前分配空间
m := make(map[string]float64) //或者
var m map[string]float64
m = make(map[string]float64)
//make为一个map分配空间时,可以指定其容量,这个容量并非是map容量的上界
m := make(map[string]float64, 100) //map底层是hashmap,容量可以减少冲突
2.非法的内存地址或空指针引用
和C、C++、Java一样,不用详细讲解
3.多值返回单值接收
和Python类似,不用详细讲解
4.数组作为函数参数内容并不会改
这点和C、C++、Java均不一样
错误代码
func Foo(a [2]int) {
a[0] = 8
}
func main() {
a := [2]int{1, 2}
Foo(a) // Try to change a[0].
fmt.Println(a) // Output: [1 2]
}
解答
数组在Go语言中是一些值,当将其传递给一个函数时,数组将会被拷贝,如果需求是需要改变其内容,可以选择用切片slice。(这点和大多数语言不同)
5.作用域问题
同一变量名在不同作用域下,并且他们有公共的作用域空间,作用域最小那个将会隐藏其他变量的值。这个与其他语言一样。
6.意外的换行
错误代码
func main() {
fruit := []string{
"apple",
"banana",
"cherry"
}
fmt.Println(fruit)
}
执行结果
../main.go:5:11: syntax error: unexpected newline, expecting comma or }
解答
在多行的切片、数组、map中每行结尾都需要有个逗号。
func main() {
fruit := []string{
"apple",
"banana",
"cherry", // comma added
}
fmt.Println(fruit) // "[apple banana cherry]"
}
6.字符串不可变
错误代码
s := "hello"
s[0] = 'H'
fmt.Println(s)
执行结果
../main.go:3:7: cannot assign to s[0]
解答
Go语言中的字符串是不可变的,其行为像只读字节切片(有少量的额外权利)。如果需要对其内容进行改变,可以使用:
buf := []rune("hello")
buf[0] = 'H'
s := string(buf)
fmt.Println(s) // "Hello"
6.字符串相加与字符相加
代码
fmt.Println("H" + "i")
fmt.Println('H' + 'i')
执行结果
Hi
177
7.TrimRight函数问题
代码
fmt.Println(strings.TrimRight("ABBA", "BA")) // Output: ""
解答
Trim,TrimLeft和TrimRight函数的第二参数并非切除的字符串,而是需要切除的集合(与C++一致,Java仅仅删除它能够去除从编码’\u0000′ 至 ‘\u0020′ 的所有字符,不能指定去除的集合)。
如果想将字符串尾部的指定字符串删除,可以用strings.TrimSuffix方法。
复制时为开辟空间
代码
var src, dst []int
src = []int{1, 2, 3}
copy(dst, src) // Copy elements to dst from src.
fmt.Println("dst:", dst) //Output: dst: []
解答
dst = make([]int, len(src)) //在copy之前开辟空间
//或者将copy语句改为
dst = append(dst, src...)
### 8.非法的++操作
错误代码
i := 0
fmt.Println(++i)
fmt.Println(i++)
执行结果
main.go:9:14: syntax error: unexpected ++, expecting expression
main.go:10:15: syntax error: unexpected ++, expecting comma or )
解答
首先、Go语言只有后置++和–操作,没有前置++和–操作;其次、Go语言不允许将后置++或者–作为表达式是使用。
为什么++和–是语句而不是表达式,为何是后置而非前置
### 9.以0开头的数字
以0开头的数字在Go语言中为8进制数。(与C、Java语言相同)
10.range更改实体
错误代码
s := []int{1, 1, 1}
for _, n := range s {
n += 1
}
fmt.Println(s)
// Output: [1 1 1]
解答
range循环将元素的值拷贝一份到临时变量中,这个和Java中的foreach语句类似。 改为:
s := []int{1, 1, 1}
for i := range s {
s[i] += 1
}
fmt.Println(s)
// Output: [2 2 2]
11.range和数组
错误代码
var a [2]int
for _, x := range a {
fmt.Println("x =", x)
a[1] = 8
}
fmt.Println("a =", a)
执行结果
x = 0
x = 0 <- Why isn't this 8?
a = [0 8]
解答
在range表达式在开始执行前,会拷贝一份数组的副本用于生成迭代值。
为了避免拷贝,可以这样做:
var a [2]int
for _, x := range a[:] {
fmt.Println("x =", x)
a[1] = 8
}
fmt.Println("a =", a)
12.Json序列化未成功
type Person struct {
name string
age int
}
p := Person{"Alice", 22}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData)) //Output:{}
解答
Go语言中需要序列化的字段需要大写。如果需要Json串中字段名确定,可以使用json:tag方式。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
p := Person{"Alice", 22}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData))
Output:{"name":"Alice","age":22}
13.空和空不同
错误代码
func Foo() error {
var err *os.PathError = nil
// …
return err
}
func main() {
err := Foo()
fmt.Println(err) // <nil>
fmt.Println(err == nil) // false
}
解答
fmt.Println(err == (*os.PathError)(nil)) // true
或者
func Foo() (err error) {
// …
return // err is unassigned and has zero value [nil, nil]
}
func main() {
err := Foo()
fmt.Println(err) // <nil>
fmt.Println(err == nil) // true
}
总结:
勤思考。
结语
不管怎么样好好加油。