生命不止,继续 go go go !!!
今天分享的是在学习、应用golang过程中,遇到的哪些错误。
左大括号不能单独一行
曾经的曾经,我们经常讨论{是在上一行的末尾,还是另起一行,也因为这个区别我们分成了左派还是右派。
对于诸如C++等语言来说,无论选择哪一种格式,只是形式不同罢了,没有对错之分。但是,对于golang就不一样了,golang中{不能单独一行:
package main
import "fmt"
func main()
{ //错误
fmt.Println("hello gopher!")
}
未使用的变量会报错,但是未使用的全局变量是不会报错的
在其他语言中,你声明了一个变量,但是没有使用它,也许是一件很轻松平常的事儿,但是对于golang来说,这就是灾难:
package main
var gvar int //不会报错
func main() {
var one int //未使用,错误
two := 2 //未使用,错误
var three int //即使被赋值了,但是未使用,错误
three = 3
func(unused string) {
fmt.Println("Unused arg. No compile error")
}("what?")
}
未使用的导入package
在C++中,不严谨的工程师会乱引入一些不需要的库,但是golang是不行的,gopher的世界中不允许这么不严谨的人存在:
package main
import (
"fmt"
)
func main() {
}
短变量声明只能在函数体内
在C++11后,给我们提供了auto关键字,用于自动推断变量的类型。在golang中没有这样的关键字,但是有短变量格式,可以不用显示的声明变量的类型。
但是,全局变量是不可以使用这种方式的。
同样,不可以重新声明已经声明过的短变量。
package main
import (
"fmt"
)
myvar := 1 //错误
func main() {
a := 100 //短变量
a := 101 //错误
a,b := 101, 202 //是可以的,:=左边至少有一个是新声明的
fmt.Println(a)
fmt.Println(b)
}
不能使用nil显示的初始化变量
The “nil” identifier can be used as the “zero value” for interfaces,functions,pointers,maps,slices,and channels.
看到了吧,nil可以干这么多事儿,但是不能把一个变量显示的声明为nil:
package main
func main() {
var x = nil //错误
var y interface{} = nil //可以
var z string = nil //错误
_ = x
_ = y
_ = z
}
空在slice和map中的不同
对于空的slice,可以添加item,但是对于空的map是不可以的:
package main
func main() {
var s []int
s = append(s,1)
var m map[string]int
m["one"] = 1 //错误
}
不能将cap内置函数用于map
package main
func main() {
m := make(map[string]int,99)
cap(m) //错误
}
数组作为函数参数传递不会退化为指针
C++程序员知道,数组名作为函数参数的时候,退化为指针,也就是不会副本。
但是,golang的世界变了,数组也是以副本的形式作为形参的:
package main
import "fmt"
func main() {
x := [3]int{1,2,3}
func(arr [3]int) {
arr[0] = 0
fmt.Println(arr) //输出 [0 2 3]
}(x)
fmt.Println(x) //输出 [1 2 3]
}
用slice代替数组作为函数参数,slice是引用类型
其实,在golang中,很少很少使用数组,也要谨慎,我们可以使用slice来代替数组完成上面的代码:
package main
import "fmt"
func main() {
x := []int{1,3}
func(arr []int) {
arr[0] = 0
fmt.Println(arr) //输出 [0 2 3]
}(x)
fmt.Println(x) //输出 [0 2 3]
}
使用range遍历遇到的坑儿
c++11中增加了基于范围的for循环,foreach,但是在golang中有range,我们先看代码:
package main
import "fmt"
func main() {
x := []string{"a","b","c"}
for v := range x {
fmt.Println(v) //输出 0,1,2
}
}
你原本想输出 a b c ,但是却输出了 0 1 2,很显然是输出了a b c 所对应的index。遇到这个坑就是对range理解的不够深刻而已,range远远比你想象的更牛,他会同时返回value和index。
这也是golang中函数的特性,可以返回多余一个的返回值!!!!
正确的代码:
package main
import "fmt"
func main() {
x := []string{"a","c"}
for _,v := range x {
fmt.Println(v) //输出 a,b,c
}
}
在string上使用index索引
首先要明确string是不可变的!!!!
package main
import "fmt"
func main() {
x := "text"
fmt.Println(x[0]) //输出 116
fmt.Printf("%T",x[0]) //输出 uint8
}
通过len获取字符串的长度
package main
import "fmt"
func main() {
data := "♥"
fmt.Println(len(data)) //prints: 3
}
使用switch遇到的坑儿
在C++中,我们知道,在switch语句中,case后如果没有break,就会顺序执行。
但是在golang的switch中,我们不需要显示的使用break关键字,也不会顺序执行:
package main
import "fmt"
func main() {
isSpace := func(ch byte) bool {
switch(ch) {
case ' ': //错误
case '\t':
return true
}
return false
}
fmt.Println(isSpace('\t'))
fmt.Println(isSpace(' '))
}
我们可以使用fallthrough,也可以一个case后面写多余一个的值:
package main
import "fmt"
func main() {
isSpace := func(ch byte) bool {
switch(ch) {
case ' ','\t':
return true
}
return false
}
fmt.Println(isSpace('\t'))
fmt.Println(isSpace(' '))
}
不允许使用前缀自增
在其他语言中,++i和i++都是允许的,但是golang中只允许使用后缀自增。并且,自增表达式不能用于表达式中:
package main
import "fmt"
func main() {
data := []int{1,3}
i := 0
++i //错误
fmt.Println(data[i++]) //错误
}