您的位置:首页 > 编程语言 > Go语言

Golang 学习摘录(一)

2015-11-17 18:08 393 查看
Golang 学习摘录(一)

学过C,python,或者Java之类语言再来学习golang应该是无压力,看看语法就能写。语法上比较特殊的如下:

声明变量并赋值使用 :=

a, b := 1, 2 //声明变量a,b,并且赋值1,2

a = 2 //a赋值2

if 不需要圆括号,并且可以执行表达式.for语句类似

if x:=1; x<2 {

}

String()函数<同java的toString(),对象的字符串形式>中如果有对自身的"%s"操作,将导致无穷递归调用。因为"%s"会调用String(),将对象转化为字符串形式。

type MyString string

func (m MyString) String() string {

return fmt.Sprintf("MyString=%s", m) // Error: will recur forever.
return fmt.Sprintf("MyString=%s", string(m)) // OK: note conversion.

}

string(m)将m转化为一个String对象,然后“%s”是作用在该String对象上,不是m本身,所以不回导致无穷递归

defer有点finally的味道,但是又有不同

for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}

Deferred functions are executed in LIFO后进先出<栈> order, so this code will cause 4 3 2 1 0

func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}

The arguments to the deferred function (which include the receiver if the function is a method) areevaluated when the defer executes, not when the call executes.

defer语句执行时,立即计算被defer的函数所需要的所有参数,而不是等到被defer的函数执行才计算该函数的参数。结果如下

entering: b
in b
entering: a
in a
leaving: a
leaving: b


new and make

new(T) returns a pointer to a newly allocated zero value of type T。new适合初始化0值对象,new(File) and &File{} are equivalent。new([]int) returns a pointer to a newly allocated, zeroed slice structure, that is, a pointer to a nil
slice value.

make(T, args) creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T)

Arrays

Arrays are values. Assigning one array to another copies all the elements.
数组不是引用,是值,数组a赋值给b,直接拷贝成另一份b,结果是数组a,b独立,内容相同


In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it. 数组作为参数,传递的也是整个数组的值的拷贝,而不是指针

以上两点与C语言不同,每次拷贝数组代价昂贵,如果希望类似C语言,可以传递指针。

Slices

Slices行为才与C的数组一致,是指针传递。Slices更常用。Slices底层是数组,只要不超过底层数组的容量,Slices地址不变。一旦添加元素导致超过底层数组的容量,就会reallocated重新分配。默认底层数组容量为cap(slice)。

特殊语法...(三个点的省略号)

x := []int{1,2,3}

y := []int{4,5,6}

x = append(x, y...)//去掉...报错,因为y不是int类型

fmt.Println(x)//有点类似Python对于字典**dict

init函数

每个源代码文件都可以有一个init函数,在该源代码文件的import语句执行完后,并且变量调用其initializers后执行init函数。一般用于检查该文件中的各种状态是否正确

import for side effect

有时候import一个library,并不是为了使用某个函数或者类,仅仅只是希望该library的init函数执行一次,做一下准备工作:

import _ "net/http/pprof"//during its init function, the net/http/pprof package registers HTTP handlers that provide debugging information


Channel

管道常用于goroutine之间的通信,同步;Go不推荐使用共享内存,互斥元等方式通信。管道用于goroutine同步例子:

c := make(chan int)  // 初始化一个不带缓存的管道
go func() {
list.Sort()
c <- 1  // Send a signal; value does not matter.
}()
//新起一个goroutine,去做排序,排序完后向管道写入数据
doSomethingForAWhile()
<-c   // 阻塞等待管道有数据写入,即等待上面goroutine排序完成

管道用作semaphore(信号量),比如限流,例子:

var sem = make(chan int, 100)
func Serve(queue chan *Request) {
for req := range queue {
tmp := req // Create new instance of req for every goroutine.
sem <- 1  //信号量满时写入阻塞
go func() {
process(tmp)
<-sem  //处理完一个请求释放一次信号量
}()
}
}

由于管道sem分配了buffer,size为100.所以前100个请求,可以不阻塞立即得到执行。后面的请求必须排队等待前面100个请求当中,有请求处理完毕(管道中有数据被读出),才能写入管道,得到处理。所以,这个例子,管道起到限流作用:并行处理的请求数不得超过100

panic recover

Go的异常处理机制,同try...except...

Because recover always returns nil unless called directly from a deferred function, deferred code can call library routines that themselves use panic and recover without failing.

func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Println("work failed:", err)
}
}()
do(work)
}

do函数里出了panic异常,执行deferred函数func,func函数里,调用recover捕获异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: