Golang学习笔记:常见问题
标签(空格分隔): golang
参考GolangFrequently Asked Questions ,很好的参考文档,理解Golang必读。
@H_502_9@1. Golang的特点和发起目的
Golang的特点以及要解决的问题概括起来就是三点:
1. concurrent : 多核 解决方式-> 语言层级并发,goroutine
2. garbage-collected language : c/c++的不足
3. fast compilation : c/c++等的不足,依赖简单,类型系统简单,非传统OO。开发更简单快捷。
这种简单设计
的特点很容易让人和C++对比,对比C++就是砍了90%特性,减少90%的麻烦。更好的对比可能是C,better c with goroutine and garbage-collection。2. Golang设计原则
- felicity of programming : 尽可能的简化代码编写规则,这点在各种解释语言,c++11等里面都可以体现一部分了,在golang上的体现就是如包的定义,编译安装,没有头文件,no forward declarations,:= 类型推断等等
- orthogonality of concepts : 另一个原则是概念设计尽可能正交orthogonal,这样理解使用会更简单。 Methods can be implemented for any type; structures represent data while interfaces represent abstraction; and so on. Orthogonality makes it easier to understand what happens when things combine.当然一旦设计正交,需要的概念也变得很少。
- speed of compilation
3. 为什么没有泛型
Generics may well be added at some point. We don’t feel an urgency for them。为什么需要泛型可以参考这篇文章,但是泛型可以带来好处也会增加复杂度,golang可能以后会添加泛型支持,目前是一个open issue。
@H_301_34@4. 为什么没有exceptions这点是golang遭受用户(尤其是c++,java用户)诟病的重要原因,实际上Golang提供了panic,recover语法类似try catch。但是个人理解为什么没有只是一个选择问题,而不是技术问题。在很多语言的编码风格里尤其是Objective-C,一般都是使用Error Object来传递错误,虽然现在try catch的性能损失可以忽略不计,但是try catch的坏处是容易滥用,导致用户忽略error和exception的区别,另外Golang提供的多返回值也方便了error传递这种风格的使用,我个人对这种设计并不反感。
5. 为什么没有assertion
和没有exceptions有点类似: programmers use them as a crutch to avoid thinking about proper error handling and reporting,当然这种牵强的说法作者自己也有点没底气:We understand that this is a point of contention. There are many things in the Go language and libraries that differ from modern practices,simply because we feel it’s sometimes worth trying a different approach。
6. 为什么build concurrency on the ideas of CSP
(Communicating Sequential Processes)
一是Erlang,Occam 等的经验,二是便于语言层面构建。7. Why goroutines instead of threads
把线程控制的复杂度从用户空间转移到语言层面(用户层面不需要关系协程还是线程,让并发的使用简单和高效是其设计目的)。The Go scheduler
8. 为什么map非线程安全
知道map非线程安全就行了,这种设计大都是一个trade off
9. Golang是面对对象语言吗
这个问题不太对,面对对象更多的是一种设计,而非语言特性,只是不同语言的实现和支持有所不同。在Golang里面的方式是interface,无type hierarchy,subclass的方式有点类似C,比C++等更general。同时Golang里面的Method也更general,可以给任何类型添加方法,总的来说的就是轻量级,更简单却能做更多事。个人觉得是Golang里最美的设计,面试官再问你会不会面对对象编程,你就打他脸。
10. 为什么Golang没有运算符或者方法重载
没什么好说的,运算符和方法重载没什么用。即使在提供这类功能的语言里面也不要使用(除非一些极端场合如数据处理框架重载+*符号用于运算矩阵,这个场合非常少,更多时候这种功能大概会带来1%的便利和1000%的代码混乱和可读性降低)。
11. interface的一个有疑问的例子Why doesn’t type T satisfy the Equal interface
type Equaler interface { Equal(Equaler) bool } type T int func (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler
因为Equaler的Equal函数需要的类型不同,正确的实现方式为
type T2 int func (t T2) Equal(u Equaler) bool { return t == u.(T2) } // satisfies Equaler 另一个例子 type Opener interface { Open() Reader } func (t T3) Open() *os.File //T3 does not satisfy Opener,although it might in another language.
Golang没有自动类型转换,也没有多态(类之间),这也是作者的trade off
12. Error和nil的一个例子
func returnsError() error { var p *MyError = nil if bad() { p = ErrBad } return p // Will always return a non-nil error. }
这和interface的实现有关:
Under the covers,interfaces are implemented as two elements,a type and a value. The value,called the interface’s dynamic value,is an arbitrary concrete value and the type is that of the value. For the int value 3,an interface value contains,schematically,(int,3).
@H_502_9@
An interface value is nil only if the inner value and type are both unset,(nil,nil). In particular,a nil interface will always hold a nil type. If we store a nil pointer of type *int inside an interface value,the inner type will be *int regardless of the value of the pointer: (*int,nil). Such an interface value will therefore be non-nil even when the pointer inside is nil.一个更直观点的例子 type myError struct{} func (this *myError) Error() string { return "" } var error1 *myError = nil var error2 error = error1// to interface => error2 != nil
13. go不支持tagged or untagged union
untagged union不安全,tagged union或者Variant types,algebraic type则和interface有重合
14. 为什么没有隐式类型转换
作者认为这种功能带来的隐患比便利要多,Golang中Int和int64都不是一个类型,不能隐式转换。
15. Why are maps,slices,and channels references while arrays are values?
知道这回事就行了slices的实现方式是对底层array的引用(见下图),参考
理解了上图再看这个例子就明白了 sa := make([]int, 10) fmt.Println("sa:",saa)//saa: [0 0 0 0 0 0 0 0 0 0] sb := saa[1:8] sb[2] = 2 sb = append(sbb, 8) //sa 也被修改了 fmt.Println("sa:",sa,"sb:",sb)// saa: [0 0 0 2 0 0 0 0 8 0] sbb: [0 0 2 0 0 0 0 8]
16. When should I use a pointer to an interface
Almost never.传一个指针指向interface大都数时候都是错误。另:The insight is that although a pointer to a concrete type can satisfy an interface,with one exception a pointer to an interface can never satisfy an interface.
17. 关于闭包的一个例子
func main() { done := make(chan bool) values := []string{"a","b","c"} for _,v := range values { go func() { fmt.Println(v) done <- true }() } // wait for all goroutines to complete before exiting for _ = range values { <-done } } // 输出是c c c 因为v共用一个变量 而输出取决于fmt.Println调用的时候v存储的数值 // 正确的写法为 for _,v := range values { go func(u string) { fmt.Println(u) done <- true }(v) } // 或者做一个本地拷贝 for _,v := range values { v := v // create a new 'v'. 注意位置 写在func里面还是不对 go func() { fmt.Println(v) done <- true }() }
18. 没有?:操作符
差评