go语法的一些细节

1. 在go中,函数参数和返回值的作用域与函数体的作用域是相同的,虽然他们在词法上出现在包裹函数体的大括号外面。

2. 注意,不像c,返回一个局部变量的地址是绝对没有问题的;变量关联的存储在函数返回之后依然存在。实际上,使用复合文字的地址也会在每次求值时分配一个新的实例。

3. 复合文字的域按顺序排列,并且必须都存在。然而通过filed:value显示的为元素添加标号,则初始化可以按任何顺序出现,没有出现的则对应为零值。

4.记住make只用于map,slice,channel,并且不返回指针。要获得一个显式的指针,使用new进行分配,或者显式的使用一个变量地址。

5. 也有接口检查是发生在运行时的。其中一个例子来自encoding/json包定义的marshal接口。当json编码器收到一个实现了marshaler接口的参数时,就调用该参数的marshaling方法来代替标准方法处理json编码。编码器利用类型断言机制在运行时进行类型检查:

m, ok:=val.(json.Mashaler)

假设我们只想知道某个类型是否实现了某个接口,而实际上不需要使用这个接口本身--例如在一段错误检查代码中,可以使用空白符忽略类型断言的返回值:

if _,ok := val.(json.Marshaler);ok {

 fmt.Printf("value %v of type %T implenments json.Marshaler\n",val,val)

}

6.带缓冲区的channel 可以像信号量一样使用,用来完成如吞吐率限制等功能。在以下示例中,到来的请求一参数的形式传入handle函数,该函数从channel中读出一个值,然后处理请求,最后再向channel写入以使“信号量”可用,以便响应下一次处理。该channel的缓冲区容量决定了并发调用process函数的上限,因此在channel初始化时,需要传入相应的容量参数。

var sem = make(chan int, MaxOutstanding)

func handle(r *Request) {
<-sem // Wait for active queue to drain.
process(r) // May take a long time.
sem <- 1 // Done; enable next request to run.
}

func init() {
for i := 0; i < MaxOutstanding; i++ {
sem <- 1
}
}

func Serve(queue chan *Request) {
for {
req := <-queue
go handle(req) // Don't wait for handle to finish.
}
}

 

7,
在golang中, 函数是第一类值(first-class object), 即函数可以赋值与被赋值. 换言之, 函数也可以作为ReceiverType, 定义自己的method. 实例:

http.HandleFunc(pattern string, handler func(ResponseWriter, *Request))

就是使用上述思想实现.

type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request){

f(w,r)

}

定义HandlerFunc类型, 本质为func(ResponseWriter, *Request). 然后定义ServeHTTP(RequestWriter, *Request)方法, 即让共实现

type Handler interface{

ServeHTTP(ResponseWriter, *Request)

}

 

posted on 2018-10-10 10:50  LeoWangY  阅读(170)  评论(0)    收藏  举报