golang 细节总结
go 刘宇帅 4年前 阅读量: 718
自增和自减
golang里包含其他语言常用的自增i++ 和自减i--,但是在golang里他们是语句而不是表达式,所以j=i++这种是错误的写法,而且golang也不支持++和--放在变量前面如++i的形式。
i++ // i的值+1
i-- // i的值-1
++i //错误
--i // 错误
j = i-- //错误
短变量声明只能在函数内部不能再外部
s := "" //错误
func main() {
s := ""
prinltln(s)
}
new只是一个预定义的函数,它并不是一个关键字
func delta(old, new int) int { return new - old } // 函数内无法调用new函数,
golang 对Unicode标示的支持
对于中文汉字,Unicode标志都作为小写字母处理,因此中文的命名默认不能导出;不过国内的用户针对该问题提出了不同的看法,根据RobPike的回复,在Go2中有可能会将中日韩等字符当作大写字母处理。
Map的遍历顺序是不确定的
Map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。在实践中,遍历的顺序是随机的,每一次遍历的顺序都不相同。这是故意的,每次都使用随机的遍历顺序可以强制要求程序不会依赖具体的哈希函数实现。如果要按顺序遍历key/value对,我们必须显式地对key进行排序,可以使用sort包的Strings函数对字符串slice进行排序。
有返回值声明的函数一定要有return吗
如果一个函数在声明时,包含返回值列表,该函数必须以 return语句结尾,除非函数明显无法运行到结尾处。例如函数在结尾时调用了panic异常或函数中存在无限循环。
golang 函数参数都是值的传递,所以无法修改实参的值
实参通过值的方式传递,因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是,如果实参包括引用类型,如指针,slice(切片)、map、function、channel等类型,实参可能会由于函数的简介引用被修改。
golang 提供优秀的垃圾回收机制,是不是所有资源都可以不用手动回收
虽然Go的垃圾回收机制会回收不被使用的内存,但是这不包括操作系统层面的资源,比如打开的文件、网络连接。因此我们必须显式的释放这些资源。
defer是return语句执行后执行的,所以可以修改返回值
func triple(x int) (result int) {
defer func() { result += x }()
return double(x)
}
fmt.Println(triple(4)) // "12"
golang里任何类型都可以声明变量?
golang里除了指针和interface其他类型都可以声明变量。
type test []int
func (t test)hello() { // 合法
fmt.Println("hello")
}
一个包含nil指针的接口不是nil接口
一个不包含任何值的nil接口值和一个刚好包含nil指针的接口值是不同的。这个细微区别产生了一个容易绊倒每个Go程序员的陷阱。 思考下面的程序。当debug变量设置为true时,main函数会将f函数的输出收集到一个bytes.Buffer类型中。
const debug = true
func main() {
var buf *bytes.Buffer
if debug {
buf = new(bytes.Buffer) // enable collection of output
}
f(buf) // NOTE: subtly incorrect!
if debug {
// ...use buf...
}
}
// If out is non-nil, output will be written to it.
func f(out io.Writer) {
// ...do something...
if out != nil {
out.Write([]byte("done!\n"))
}
}
我们可能会预计当把变量debug设置为false时可以禁止对输出的收集,但是实际上在out.Write方法调用时程序发生了panic:
if out != nil {
out.Write([]byte("done!\n")) // panic: nil pointer dereference
}
当main函数调用函数f时,它给f函数的out参数赋了一个bytes.Buffer的空指针,所以out的动态值是nil。然而,它的动态类型是bytes.Buffer,意思就是out变量是一个包含空指针值的非空接口(如图7.5),所以防御性检查out!=nil的结果依然是true。
Go 语言中内部类型方法
- 在派生类没有改写基类的成员方法时,相应的成员方法被继承。
- 派生类可以直接调用基类的成员方法,譬如基类有个成员方法为Base.Func(),那么Derived.Func()等同于Derived.Base.Func()
- 倘若派生类的成员方法名与基类的成员方法名相同,那么基类方法将被覆盖或叫隐藏,譬如基类和派生类都有成员方法Func(),那么Derived.Func()将只能调用派生类的Func()方法,如果要调用基类版本,可以通过Derived.Base.Func()来调用。
- 基类采用指针方式的组合,依然具有派生的效果,只是派生类创建实例的时候需要外部提供一个基类实例的指针。