$ bash < <(curl -s https://raw.github.com/moovweb/gvm/master/binscripts/gvm-installer)
$ vim .zshrc
[[ -s "$HOME/.gvm/scripts/gvm" ]] && source "$HOME/.gvm/scripts/gvm"
$ gvm install go1.0.3
$ gvm use go1.0.3 [--default]
$ echo $GOROOT
$ echo $GOPATH
$ mkdir $GOPATH/src/helloworld # 创建helloworld工程目录
$ atom $GOPATH/src/helloworld/hello.go # 创建helloworld工程的源文件
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, 世界")
}
$ go install helloworld # 编译安装helloworld工程
$ helloworld # 运行helloworld工程
var a int = 12 // 定义一个类型为int的变量a并初始化值为12
var b int // 定义一个类型为int的变量b默认初始化为0
var c = 15 // 定义一个变量c并初始化值为13,类型自动推导
var d, e int = 12, 16 // 变量d,e的类型都是int
var d, e = 19, "abc" // 同时定义多个变量,并根据值来推导类型
var( // 与上面定义变量的方式一样
d = 19
e = "abc"
)
f := 16 // 使用“:=”可以更简洁地定义变量,但不能在函数外使用这种方法定义变量
_, g := 12, 16 // “_”是一个特殊的变量名,赋予它的值都会被丢弃,变量e的值是16
// 注意事项:定义的变量未使用编译过程会报错
关键字: var
与 :=
const Pi = 3.1415926
关键字: const
bool // 布尔值
string // 字符串,不可变
int int8 int16 int32 int64 // 带符号整形
uint uint8 uint16 uint32 uint64 uintptr // 不带符号整形
byte // uint8 的别名
rune // int32 的别名,代表一个Unicode码点,可以遍历字符串每个字符
float32 float64 // 浮点数,默认是float64
complex64 complex128 // 复数
error // 错误类型
iota
枚举const(
x = iota // x == 0
y = iota // y == 1
z = iota // z == 2
w // 常量声明省略值时,默认和之前一个值的字面相同。这里隐式地说w = iota,因此w == 3。其实上面y和z可同样不用"= iota"
)
const v = iota // 每遇到一个const关键字,iota就会重置,此时v == 0
var a1 [5]int // 声明了一个长度为5的int数组
a := [3]int{1, 2, 3} // 声明了一个长度为3的int数组
b := [10]int{1, 2, 3} // 声明了一个长度为10的int数组,其中前三个元素初始化为1、2、3,其它默认为0
c := [...]int{4, 5, 6} // 可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度
// 声明了一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// 如果内部的元素和外部的一样,那么上面的声明可以简化,直接忽略内部的类型
easyArray := [2][4]int{ {1, 2, 3, 4}, {5, 6, 7, 8} }
slice
指向数组的值p := []int{1, 2, 3, 4, 5} // 与声明数组一样,只是少了长度
// slice的应用
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
var a, b []byte
a = ar[0:1] // a = ['a']
a = ar[2:6] // a = ['c', 'd', 'e', 'f']
b = ar[:4] // b = ['a', 'b', 'c', 'd']
b = ar[:] // b = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
len(ar)
cap(ar)
append(a, 'h')
map
var a map[string] int
map["a"] = 1
map["b"] = 2
b := map[string] int {"a":1, "b":2, "c":3}
value, ok = b["a"] // 如果a存在,则ok为true,否则为false
if (ok)
{
// value = 1
}
else
{
// value = 0
}
len(a) // 返回a拥用key的个数,输出2
delete(a, "a") // 从a中删除key为a的记录
make
是给map
、slice
和channel
分配内存的
new
是给各种类型分配内存的
a := make([]int, 5) // 分配一个长度为5,容量为5的int类型的数组,默认值为[0, 0, 0, 0, 0]
b := make([]int, 2, 5) // 分配一个长度为2,容量为5的int类型的数组,默认值为[0, 0]
c := make(map[int]string)
range
// for 循环的 range 格式可以对 slice 或者 map 进行迭代循环
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow { // i表示为下标,v表示为值
fmt.Printf("2**%d = %d\n", i, v)
}
for _, v := range pow { // 省略下标,v表示为值
fmt.Printf("%d\n", v)
}
for i := range pow { // 省略值
fmt.Printf("%d\n", i)
}
if
if a > 10 { // 不需要“()”
// true
} else {
// false
}
// 条件中存在变量,作用域在if范围内
if i := getVaule(); i > 10 {
// true
} else {
// false
}
for
for i := 0; i < 10; i++ { // 不需要“()”
}
a := 0
for ;a < 10; { // 省略前置和后置
a++
}
for a < 10 { // 可以省略“;”分号
}
for ;; { // 死循环
}
for { // 死循环
}
switch
switch i { // 同时i也支持i := getVaule()这种形式
case 1:
// 匹配成功后会自动终止,不需要break
case 2:
//
case 5, 10, 15, 20:
// 使用“,”表示"or",i等于这些值时会执行
defaule:
//
}
switch i := getVaule(); i { // 局部变量
//
}
switch { // 没有条件,为true,会从上往下匹配
case a > 10:
//
case a < 10:
//
case a == 5: fallthrough
case a == 6:
// 当a等于5或6时会执行这里,必须使用fallthrough才会继续向下匹配
}
func add(x int, y int) int { // 接收两个int类型的参数,返回值是int类型
return x + y
}
func add(x, y int) int { // 同上,当参数类型相同时可省略前面参数的类型声明
return x + y
}
func get()(string, string) { // 函数可以返回任意数量的返回值
return "a", "b"
}
func result()(a, b string) { // 把a,b变量当作返回值返回
a := "abc"
b := "def"
return
}
func do(args ...int) { // 接收不定数量的int类型的参数,args是一个slice
for i := 0; i < len(args); i++ {
args[i]
}
}
func br(a *int) { // 指针传递,参数应该使用“&”取地址符
}
func la(a int) {
...
defer a := 0 // a := 0会在la函数结束时执行,类似于try中的finally
}
a := func(b int) int { // 有点类似于javascript中的函数定义
return b + 10
}
a(12)
type
函数也可以作为变量或类型使用
type a func(b int) int // 声明一个函数类型
func a1(b int) int { // 函数类型的一个实现1
}
a2 := func(b int) int { // 函数类型的一个实现2
}
func c(x int, y a) { // 声明一个接收两个参数的函数,第二个参数是函数类型
y(x) // 调用函数类型y处理x参数
}
c(10, a1) // 使用示例1
c(15, a2) // 使用示例2
func a() func() int {
b := 0
return func() int {
return b + 10
}
}
这两个函数都是系统自动调用的,不需要手动调用
func main() { // 只有package main时main函数才会被调用,并作为入口函数
}
func init() { // 在任意包下都有一个init函数,系统自动调用
}
type s struct { // 声明一个拥有两个成员变量的s结构体
X int
Y int
}
a := s{X:12, Y:98} // 初始化方式1
b := s{20, 50} // 初始化方式2
a.X // 以“.”为访问结构体的字段
type s1 struct {
s // 这里就把上面定义的结构引进来,也叫做匿名字段
x int
}
a := s1{s{10, 20}, 30}
fmt.Println(a.s.X, a.s.Y, a.X, a.Y, a.x) // 匿名字段可以使用字段来访问也可以直接通过结构体来访问,如果字段重复,最外层的优先
type Student struct { // 定义一个Student结构体
age int
name string
}
func (s Student) say(str string) { // 为Student结构体定义一个say方法,接收一个string类型的参数
s.age = 20 // 此处修改是无效的
fmt.Println(str)
}
s := Student{18, "Tom"} // 实例化Student结构体
s.say("hello") // 调用结构体的say方法
func (s *Student) say(str string) { // 为Student结构体指针定义一个say方法,使用指针能够修改结构体的字段值
s.age = 25 // 此处修改有效,因为是指针
fmt.Println(str)
}
s := &Student{20, "Lin"}
s.say("world")
type s1 struct {
age int
}
type s2 struct {
s1
}
func (m *s1) hello(str string) {
}
a := s1{10}
b := s2{s1{15}}
a.hello("Hello")
b.hello("World")
type s1 struct {
age int
}
type s2 struct {
s1
}
func (m *s1) hello(str string) {
}
func (m *s2) hello(str string) { // 重载方法
}
a := s1{10}
b := s2{s1{15}}
a.hello("Hello")
b.s1.hello("Hello World") // 访问匿名结构体的方法
b.hello("World") // 访问重载后的方法
type Face interface { // 定义一接口,方法的集合
sayHi()
sing()
}
func (a *A) sayHi() { // 结构体实现了Face接口的sayHi()方法
}
func (a *A) sing() { // 结构体实现了Face接口的sing()方法
// 这样,结构体就实现了Face接口的所有方法,即结构体实现了Face接口
}
type Face interface { // 定义一接口,方法的集合
sayHi()
sing()
}
type f Face // interface值
f := A{} // 类似于java中的实现与接口
f.sayHi() // 调用抽象接口的方法
// 定义a为空接口
var a interface{}
var i int = 5
s := "Hello world"
// a可以存储任意类型的数值
a = i
a = s
func p(i interface{}) { // 接收任意类型的参数
value, ok := i.(string) // 实现类型判断,如果i是string类型的变量,则ok等于true,value就是i的值
}
p(i)
p(s)
一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。
type I1 interface {
sayHi() string
add(x, y int) int
}
type I2 interface {
I1 // 嵌入一个interface,即I2包含I1的所有方法
}
func say(str string) {
fmt.Println(str)
}
func main() {
go say("hello") // 开启新的goroutine执行
say("World")
}
关键字: go
channel
ci := make(chan int) // 创建一个channel
cs := make(chan string) //
a := 10
ci <- a // 把a的值发送给ci
b := <- ci // 从ci中接收数据赋值给b,这步应该是在新goroutine中执行的
// 执行“<-”发送或接收之前时会阻塞,直到读取到了值,即发送与接收是一起的
关键字: chan
channel
ci := make(chan int, x) // x为缓冲的长度,在x允许的长度内发送与接收都不会阻塞,当超过
range
和close
ci := make(chan int, 10) // 创建一个缓冲长度为10的channel
for i := 0; i < cap(ci); i++ {
ci <- i
}
close(ci) // 发送完数据就关闭channel
for v := range ci {
fmt.Println(v)
}
select
select {
case <- :
case <- :
default:
// 不阻塞时执行这里
}