基本是边看视频边做笔记。

视频地址

注意以上视频需要有safaribooks的账号才能收看。个人用户3000日元/月,
比那些月付成人视频网站性价比高多了。当然,我用的是公司买下的企业子账号。

:=是什么

变量申明

1
var my_var

变量赋值

1
2
var my_var Int
my_var = 1

申明并赋值

1
2
3
4
var my_var = 1
// 或者
my_var := 1

由于已经赋初值,所以变量的类型可以省略。
另外注意 :=的形式只能用在函数中。否则会出现类似

1
expected declaration, found 'IDENT'

的编译错误提示。

变量的scope

在go中,外部scope中定义的变量可以在内部scope中access。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"
var my_var = "myvar"
func main() {
myscope()
}
func myscope() {
fmt.Println(my_var)
}
#=> myvar

这点和Javascript类似。

1
2
3
4
5
6
7
8
9
> var my_var = 1
undefined
> function myfunc(){
... console.log(my_var)
... }
undefined
> myfunc()
1
undefined

而在Ruby中,method内部是无法获取外部的变量值的。

1
2
3
4
5
6
7
8
9
10
11
irb(main):001:0> my_var = "myvar"
=> "myvar"
irb(main):002:0> def myfunc
irb(main):003:1> print my_var
irb(main):004:1> end
=> :myfunc
irb(main):005:0> myfunc
NameError: undefined local variable or method `my_var' for main:Object
from (irb):3:in `myfunc'
from (irb):5
from /Users/gyorou/.anyenv/envs/rbenv/versions/2.3.3/bin/irb:11:in `<main>'

在Ruby中,scope的边界取决于def, class, module 这类关键词。但是我们使用block来打开scope的边界。

1
2
3
4
5
6
irb(main):009:0> define_method(:myfunc2) do
irb(main):010:1* print my_var
irb(main):011:1> end
=> :myfunc2
irb(main):012:0> myfunc2()
myvar=> nil

iota

golang 的 Const常量中已经定义的递增的隐含变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main
import "fmt"
const (
zero = iota
one = iota
two = iota
three = iota
)
func main() {
fmt.Printf("zero:%v\n", zero)
fmt.Printf("one:%v\n", one)
fmt.Printf("two:%v\n", two)
fmt.Printf("three:%v\n", two)
}
//=> result
zero:0
one:1
two:2
three:3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const (
January Month = 1 + iota
February //2
March //3
April //4
May //5
June //6
July //7
August //8
September //9
October //10
November //11
December //12
)
1
2
3
4
5
6
7
8
9
const (
a0 = iota // 0 初始化
a1 // 1
a2 // 2
a3 = 10
a4 // 10
a5 = iota // 5(a3 a4 未使用iota,但是iota保持递增)
a6 // 6
)

从中可以看到的规律是,下一个变量的默认值的计算公式总是和上一个变量相同,唯一变化的是下一个变量的iota会增加1。

array and slice

array 属于value, 而slice则是引用。
在go中array应用场景不多,尽量使用slice。

map

key 的顺序无法保证。如果我们要保证输出的顺序,则可以抽取所有的key生成array之后,排序,然后按照key来取相对的值。

type and interface

定义一个HttpRequest类型

1
2
3
4
5
type HttpRequest struct {
url string
header map[string]string
body string
}

于是我们可以定义这个type的method。

1
2
3
func (http *HttpRequest) GetBody() string {
return http.body
}

完整程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import "fmt"
type HttpRequest struct {
url string
header map[string]string
body string
}
func (http *HttpRequest) GetBody() string {
return http.body
}
func main() {
http := HttpRequest{"www.bocchi.tokyo", map[string]string{}, "fuck your mother"}
fmt.Println(http.GetBody())
}

输出结果fuck your mother

对于任何type我们都可以定义method。

1
2
3
4
type Hex int
func (h Hex) String() string {
return fmt.Sprintf("0x%x", int(h))
}

甚至函数也可以定义自己的method。

1
2
3
4
type HandlerFunc func(w ResponseWriter, r *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

下面再看 interface

1
2
3
type Handler interface {
ServeHTTP(w ResponseWriter, r *Request)
}

Golang中不需要明确指明我们的某个type实现了某个interface,我们只需要实现同名的method就行了。

例如上面,我们的HandlerFunc类型就已经实现了handler的interface,所以我们可以有如下的用法啦。

1
2
3
4
5
6
f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello, world")
})
// func Handle(pattern string, handler Handler)
http.Handle("/", f)

更多参考