变量名由字母、数字、下划线组成,不能以数字开头。
var ( A int //默认为0 B string //默认为"" C bool //默认为false Name string = "suoning" Age = 18 // 自动识别类型 ) func main() { sex := "man" //等价于 var sex string = "man" var girlfriend string //声明变量 girlfriend = "Dawn" //变量赋值 Name := "Nick" //正确 //girlfriend := "Jenny" //错误的!不能申明两次 ... }
常量使用const 修饰,代表永远是只读的,不能修改。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
语法:const identifier [type] = value,其中type可以省略。
iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。
const ( A = 'a' //97 B = iota //1 C //2 D = "nick" //"nick" iota += 1 E //"nick" iota += 1 F = 618 //618 iota +=1 G //618 iota +=1 H = iota //7 I //8 )
基本数据类型
布尔型的值只可以是常量 true 或者 false。
数字类型
int:
- uint8(无符号 8 位整型 (0 到 255))
- uint16(无符号 16 位整型 (0 到 65535))
- uint32(无符号 32 位整型 (0 到 4294967295))
- uint64(无符号 64 位整型 (0 到 18446744073709551615))
- int8(有符号 8 位整型 (-128 到 127))
- int16(有符号 16 位整型 (-32768 到 32767))
- int32(有符号 32 位整型 (-2147483648 到 2147483647))
- int64(有符号 64 位整型 (-9223372036854775808 到 9223372036854775807))
float:
- float32(IEEE-754 32位浮点型数)
- float64(IEEE-754 64位浮点型数)
- complex64(32 位实数和虚数)
- complex128(64 位实数和虚数)
其它:
- byte(类似 uint8)
- rune(类似 int32)
- uint(32 或 64 位)
- int(与 uint 一样大小)
- uintptr(无符号整型,用于存放一个指针)
字符类型
存储为ascii码
var a byte = 'a' fmt.Println(a) //97
字符串类型
字符串表示两种方式:
双引号
`` (反引号,不转义)
string底层就是一个byte的数组
string本身是不可变的,因此要改变string中字符,需要如下操作:
str := "hello world"
s := []byte(str)
s[0] = 'o'
str = string(s)
If/else & for & range
注意 else if / else 位置
if condition1 {
} else if condition2 {
} else if condition3 {
} else {
}
for循环条件没有小括号
for i := 0; i < 10; i++ {
}
死循环
for true {
}
可以简写为:
for {
}
range
for i, v := range str {
}
package main
import (
"fmt"
)
func ran(str string) {
for i, v := range str {
fmt.Printf("index[%d] val[%c] len[%d] ", i, v, len([]byte(string(v))))
}
}
func main() {
ran("Love, 索宁")
}
switch case
Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch。
func sw(num int) { switch num { case 1, 2, 3: fmt.Printf("%s in 1,2,3 ", num) case 4, 5, 6: fmt.Printf("%s in 4,5,6 ", num) fallthrough case 7, 8, 9: fmt.Printf("%s big 789 ", num) default: fmt.Printf("default... ") } }
main & init & defer
main & init
Go程序会自动调用init()和main(),所以你不需要在任何地方调用这两个函数。
defer
- 当函数返回时,执行defer语句;
- 多个defer语句,按先进后出的方式执行;
- defer语句中的变量,在defer声明时确定变量。
- 触发异常也会走defer语句。
package main import "fmt" //声明defer时,变量i就为0 func test1() { i := 0 defer fmt.Println(i) i++ return } //栈,先进先出 func test2() { for i := 0; i < 5; i++ { defer fmt.Printf("->%d", i) } } func main() { test1() test2() }
闭包
闭包是一个函数和与其相关的引用环境组合而成的实体。
函数可以存储到变量中作为参数传递给其它函数,能够被函数动态的创建和返回。
func Adder() func(int) int { var x int return func(d int) int { x += d return x } } f := Adder() fmt.Println(f(1)) //1 fmt.Println(f(10)) //11 fmt.Println(f(100)) //111
值传递 & 引用传递
无论是值传递,还是引用传递,传递给函数的都是变量的副本;
值传递是值的拷贝,引用传递是地址的拷贝;
一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
map、slice、chan、指针、interface默认以引用的方式传递。
new 内置函数 用来分配内存,主要用来分配值类型,比如int、struct,返回的是指针;
make 内置函数 用来分配内存,主要用来分配引用类型,比如chan、map、slice。
程序初始化与执行过程
指针类型(&*)
普通类型,变量存的就是值,也叫值类型;
指针类型,变量存的是一个地址,这个地址存的才是值。
变量是一种占位符,用于引用计算机内存地址;
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
获取指针类型所指向的值,使用:*。
一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址。
申明如下:
var age *int //指向整型 var height *float32 //指向浮点型
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
栗子
package main import "fmt" func main() { var ptr *int num := 100 ptr = &num fmt.Println(ptr) //0xc42000e1f8 fmt.Println(*ptr) //100 *ptr = 200 fmt.Println(num) //200 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
package main; import ( "time" "fmt" ) func main() { //time.Time代表一个纳秒精度的时间点 var t time.Time; //返回当前时间 t = time.Now(); fmt.Printf( "%v
" , t); //反回所在时区 fmt.Printf( "%v
" , t.Location()); //返回UTC时间和UTC时区 fmt.Printf( "%v %v
" , t.UTC(), t.UTC().Location()); //同上,In()返回指定时区的时间 fmt.Printf( "%v %v
" , t.In(time.UTC), t.In(time.UTC).Location()); //返回当地时区的时间 fmt.Printf( "%v %v
" , t.Local(), t.Local().Location()); //根据时间戳返回本地时间 //参数分别表示秒数和纳秒数 t2 := time.Unix(1487780010, 0); fmt.Println(t2); //根据指定时间返回time.Time //分别指定年,月,日,时,分,秒,纳秒,时区 t3 := time.Date(2017, time.Month(5), 26, 15, 30, 20, 0, t.Location()); fmt.Println(t3); //格式化输出时间 t4 := time.Now(); fmt.Println(t4.Format( "2006-01-02 15:04:05" )); //获取时间信息 t5 := time.Now(); //返回日期 fmt.Println(t5.Date()); //返回年 fmt.Println(t5.Year()); //返回月 fmt.Println(t5.Month()); //返回日 fmt.Println(t5.Day()); //返回星期 fmt.Println(t5.Weekday()); //返回ISO 9601标准下的年份和星期编号 fmt.Println(t5.ISOWeek()); //返回时分秒 fmt.Println(t5.Clock()); //返回小时 fmt.Println(t5.Hour()); //返回分钟 fmt.Println(t5.Minute()); //返回秒 fmt.Println(t5.Second()); //返回纳秒 fmt.Println(t5.Nanosecond()); //返回一年中对应的天 fmt.Println(t5.YearDay()); //返回时区 fmt.Println(t5.Location()); //返回时区的规范名,时区相对于UTC的时间偏移量(秒) fmt.Println(t5.Zone()); //返回时间戳 fmt.Println(t5.Unix()); //返回纳秒时间戳 fmt.Println(t5.UnixNano()); //时间的比较与计算 t6 := time.Now(); //是否零时时间 fmt.Println(t6.IsZero()); //t6时间在t5时间之后,返回真 fmt.Println(t6.After(t5)); //t5时间在t6时间之前,返回真 fmt.Println(t5.Before(t6)); //时间是否相同 fmt.Println(t6.Equal(t6)); //返回t6加上纳秒的时间 fmt.Println(t6.Add(10000)); //返回两个时间之差的纳秒数 fmt.Println(t6.Sub(t5)); //返回t6加1年,1月,1天的时间 fmt.Println(t6.AddDate(1, 1, 1)); //时间的序列化 t7 := time.Now(); //序列化二进制 bin, _ := t7.MarshalBinary(); //反序列化二进制 t7.UnmarshalBinary(bin) fmt.Println(t7); //序列化json json, _ := t7.MarshalJSON(); fmt.Println(string(json)); //反序列化json t7.UnmarshalJSON(json); fmt.Println(t7); //序列化文本 txt, _ := t7.MarshalText(); fmt.Println(string(txt)); //反序列化文本 t7.UnmarshalText(txt); fmt.Println(t7); //gob编码 gob, _ := t7.GobEncode(); t7.GobDecode(gob); fmt.Println(t7); //时间段time.Duration dur := time.Duration(6666666600000); //返回字符串表示 fmt.Println(dur.String()); //返回小时表示 fmt.Println(dur.Hours()); //返回分钟表示 fmt.Println(dur.Minutes()); //返回秒表示 fmt.Println(dur.Seconds()); //返回纳秒表示 fmt.Println(dur.Nanoseconds()); //时区time.Location //返回时区名 fmt.Println(time.Local.String()); //通过地点名和时间偏移量返回时区 fmt.Println(time.FixedZone( "Shanghai" , 800)); //通过给定时区名称,返回时区 loc, _ := time.LoadLocation( "Asia/Shanghai" ); fmt.Println(loc); //阻塞当前进程3秒 time.Sleep(time.Second * 3); //定时器time.Timer //创建一个1秒后触发定时器 timer1 := time.NewTimer(time.Second * 1); <-timer1.C; fmt.Println( "timer1 end" ); //1秒后运行函数 time.AfterFunc(time.Second * 1, func () { fmt.Println( "wait 1 second" ); }); time.Sleep(time.Second * 3); //打点器time.Ticker //创建一个打点器,在固定1秒内重复执行 ticker := time.NewTicker(time.Second); num := 1; for { if num > 5 { //大于5次关闭打点器 ticker.Stop(); break ; } //否则从打点器中获取chan select { case <-ticker.C: num++; fmt.Println( "1 second..." ); } } } |
} else if condition2 { } else if condition3 { } else { }
for循环条件没有小括号
for i := 0; i < 10; i++ { }
死循环
for true { } 可以简写为: for { }
range
for i, v := range str { }
package main import ( "fmt" ) func ran(str string) { for i, v := range str { fmt.Printf("index[%d] val[%c] len[%d] ", i, v, len([]byte(string(v)))) } } func main() { ran("Love, 索宁") }