Go语言
Go 语言最主要的特性:
-
自动垃圾回收
-
更丰富的内置类型
-
函数多返回值
-
错误处理
-
匿名函数和闭包
-
类型和接口
-
并发编程
goroute,轻量级线程,创建成千上万个goroute成为可能
基于CSP(Communicating Sequential Process)模型实现
func main(){ go fmt.Println("Hello world!") }
-
反射
-
语言交互性
-
channel
-
管道,类似unix/linux中的pipe
-
多个goroutine之间通过channel进行通信
-
支持任何类型
package main func main(){ pipe := make(chan int , 3) pipe <- 1 pipe <- 2 pipe <- 3 } //取数据
-
结构
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
Hello world
package main
import "fmt"
func main(){
/* 这是第一个程序 */
fmt.Println("Hello world!")
}
- 第一行代码
package main
定义了包名,package main表示一个可独立执行的程序,每个go应用程序包含一个名为main的包.- 第二行
import "fmt"
告诉 Go编译器,这个程序需要使用fmt包的函数,或其他元素,fmt包实现了格式化IO(输入/输出)的函数.- 第三行
func main()
是程序开始执行的函数,main函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有int()函数则会先执行该函数).- 第四行
/*...*/
是注释,在程序执行时将被忽略.单行注释是最常见的注释形式,多行注释也叫块注释- 第五行
fmt.Println(...)
可以将字符串输入到控制台.- 当标识符(包括常量,变量,类型,函数名,结构字段等等)以一个大写字母开头.使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的public);标识符如果以小写字母开头,则对包外是可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的protected).
Go标记
fmt.Println("Hello world!")
行分隔符
在Go程序中,一行代表一个语句结束.
注释
// 单行注释
/*
多行注释,或称块注释
*/
标识符
标识符用来命名变量,类型等程序实体,一个标识符实际上就是一个或是多个字母(
A~Z
和a~z
)数字(0~9
),下划线~
组成的序列,但是第一个字符必须是字母下划线而不是数字
关键字
25个关键字或保留字
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
36个预定义标识符
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
---|---|---|---|---|---|---|---|---|
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
程序一般由关键字,常量,变量,运算符,类型和函数组成
程序中可能会使用到这些分隔符:括号
()
,中括号[ ]
和大括号{ }
程序中可能会使用到这些标点符号:
.
,
;
和...
Go语言的空格
Go语言中变量的声明必须使用空格隔开
var age int;
Go语言数据类型
在Go编程语言中,数据类型用于声明函数和变量
数据类型的出现是味蕾把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,可充分使用内存
类型 | 描述 |
---|---|
布尔型 | 布尔型的指只可以是常量true和false |
数字类型 | 整型int和浮点型float32,float64,Go语言支持整型和浮点型数字,并且原声支持复数,其中位的运算采用补码 |
字符串类型 | 字符串就是一串固定长度的字符连接起来的字符序列,Go的字符串是有单个字节连接起来.Go语言的字符串的字节使用UTF-8编码标识Unicode文本 |
派生类型 | *指针类型(Pointer) *数组类型 *结构化类型(struct) *Channel类型 *函数类型 *切片类型 *接口类型(interface) *Map类型 |
数字类型
类型 | 描述 |
---|---|
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) |
浮点型
类型 | 描述 |
---|---|
float32 | IEEE-754 32位浮点型数 |
float64 | IEEE-754 64位浮点型数 |
complex64 | 32位实数和虚数 |
complex128 | 64位实数和虚数 |
其他数字类型
类型 | 描述 |
---|---|
byte | 类似uint8 |
rune | 类似int32 |
uint | 32或64位 |
int | 与uint一样大小 |
uintptr | 无符号整型,用于存放一个指针 |
Go语言变量
变量来源数学,是计算机语言中能存储计算结果或能表示值抽象概念,变量可以通过变量名访问
Go语言变量名由字母,数字,下划线组成,其中首个字母不能为数字
- 声明变量一般形式是使用var关键字
var identifier type
变量声明
- 指定变量类型,声明后若不赋值,使用默认值
var v_name v_type
v_name = vlaue
- 根据值自行判定变量类型
var v_name = value
- 省略var 注意: =左侧的变量不应该是已经声明过的,否则导致编译错误
v_name := value
var a int = 10
var b = 10
c := 10
多变量声明
package main
var x,y int
var(
a int
b bool
)
var c, d int = 1, 2
var e, f = 123, "hello"
//这种不带声明格式的只能在函数体中出现
//g,h := 123, "hello"
func main(){
g,h := 123, "hello"
println(x,y,a,b,c,e,f,g,h)
}
输出结果
0 0 0 false 1 123 hello 123 hello
在相同的代码块中,不可以再次对于相同名称的变量使用初始化声明
package main
import "fmt"
var a string = "abc"
func main(){
fmt.Print("hello world!",a,"
")
a = "bdc"
fmt.Print("hello world!",a,"
")
b := "Hello world!"
fmt.Print(b)
}
输出结果
hello world!abc
hello world!bdc
Hello world!
Go语言常量
常量是一个简单的标识符,在程序运行时,不会被修改的量
常量中的数据类型只可以是布尔型, 数字型(整数型,浮点型和复数) 和 字符串型
const identifier [type] = value
常量类型
- 显式类型定义: const b string = "abc"
- 隐式类型定义: const b = "abc"
多个相同类型的声明
const c_name1, c_name2, c_name3 = value1, value2, value3
package main
import "fmt"
func main(){
const LENGTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" // 多重赋值
area = LENGTH * WIDTH
fmt.Printf("面积为: %d",area)
println()
println(a,b,c)
}
输出结果
面积为: 50
1 false str
常量用作枚举
package main
import "unsafe"
const(
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
func main(){
println(a,b,c)
}
输出结果
abc 3 16
iota
iota 特殊常量 可以认为是一个可以被编译器修改的常量
在每一个const关键字出现时, 被重置为0, 然后在下一个const出现之前, 每出现一次iota, 其所代表的数字会自动增加1
iota 用作 枚举值
package main
import "fmt"
func main(){
const(
a = iota
b = iota
c = iota
)
fmt.Printf("a = %d, b = %d, c = %d ",a,b,c)
const(
e = iota
f
g
)
fmt.Printf("e = %d, f = %d, g = %d ",e,f,g)
}
输出结果
a = 0, b = 1, c = 2 e = 0, f = 1, g = 2
package main
import "fmt"
func main(){
const(
a = iota //0
b //1
c = 3 //3
d = "ha" //独立值, iota += 1
e // "ha", iota += 1
f = 100 // iota += 1
g //100 iota += 1
h = iota //7 恢复计数
i //8
)
fmt.Printf("a = %d, b = %d, c = %d , d = %s, e = %s, f = %d, g = %d, h = %d, i = %d",a,b,c,d,e,f,g,h,i)
}
输出结果
a = 0, b = 1, c = 3 , d = ha, e = ha, f = 100, g = 100, h = 7, i = 8
package main
import "fmt"
const (
i = 1 << iota // i = 1:左移0位,不变仍为1
j = 3 << iota // j = 3:左移1位,变为二进制110, 即6
k // k = 3:左移2位,变为二进制1100, 即12
l // l = 3:左移3位,变为二进制11000, 即24
)
func main(){
fmt.Println("i = ",i)
fmt.Println("j = ",j)
fmt.Println("k = ",k)
fmt.Print("l = ",l)
}
输出结果
i = 1
j = 6
k = 12
l = 24
Go语言运算符
Go语言内置的运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符
算术运算符
运算符 | 描述 |
---|---|
+ | 相加 |
- | 相减 |
* | 相乘 |
/ | 相除 |
% | 求余 |
++ | 自增 |
-- | 自减 |
关系运算符
运算符 | 描述 |
---|---|
== | 检查两个值是否相等 |
!= | 检查两个值是否不相等 |
> | 检查左边值是否大于右边值 |
< | 检查右边值是否大于左边值 |
>= | 检查左边值是否大于等于右边值 |
<= | 检查右边值是否大于等于左边值 |
逻辑运算符
运算符 | 描述 |
---|---|
&& | 逻辑AND运算符 |
|| | 逻辑OR运算符 |
| | 逻辑NOT运算符 |
位运算符
p | q | p&q | p|q | p^q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
运算符 | 描述 |
---|---|
& | 按位与运算符& 是双目运算符 |
| | 按位或运算符| 是双目运算符 |
^ | 按位异或运算符^ 是双目运算符 |
<< | 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 |
>> | 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。 |
赋值运算符
运算符 | 描述 |
---|---|
= | 简单的赋值运算符,将一个表达式的值赋值给一个左值 |
+= | 相加后再赋值 |
-= | 相减后再赋值 |
/= | 相除后再赋值 |
%= | 求余后再赋值 |
<<= | 左移后再赋值 |
>>= | 右移后再赋值 |
&= | 按位与后赋值 |
^= | 按位异或后赋值 |
|= | 按位或后赋值 |
*= | 相乘后再赋值 |
其他运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a;将给出变量的实际地址 |
* | 指针变量 | *a;是一个指针变量 |
运算符优先级
优先级由高到低
优先级 | 运算符 |
---|---|
7 | ^ ! |
6 | * / % << >> & &^ |
5 | + - | ^ |
4 | == != < <= >= > |
3 | <- |
&& | |
1 | || |
Go语言条件语句
if语句
package main
import "fmt"
func main(){
//定义局部变量
var a int = 10
//使用 if 语句判断布尔表达式
if a < 20{
//如果条件为true则执行以下语句
fmt.Printf("a 小于 20
")
}
fmt.Printf("a的值为:%d
",a)
}
输出结果
a 小于 20
a的值为:10
if ... else ...语句
package main
import "fmt"
func main(){
//定义局部变量
var a int = 100
//判断布尔表达式
if a < 20{
//如果条件true,则执行以下语句
fmt.Printf("a 小于 20
")
}else{
//如果条件false,则执行以下语句
fmt.Printf("a 不小于 20
")
}
fmt.Printf("a的值为:%d
",a)
}
输出结果
a 不小于 20
a的值为:100
if嵌套语句
package main
import "fmt"
func main(){
//定义局部变量
var a int = 100
var b int = 200
//判断布尔表达式
if a == 100{
//如果条件true,则执行以下语句
if b == 200{
//如果条件true,则执行以下语句
fmt.Printf("a 的值为 100, b 的值为 200
")
}
}
fmt.Printf("a的值为:%d
",a)
fmt.Printf("b的值为:%d
",b)
}
输出结果
a 的值为 100, b 的值为 200
a的值为:100
b的值为:200
Switch语句
package main
import "fmt"
func main(){
//定义局部变量
var grade string = "B"
var marks int = 90
switch marks{
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default:
grade = "D"
}
switch {
case grade == "A":
fmt.Printf("优秀
")
case grade == "B", grade == "C":
fmt.Printf("良好
")
case grade == "D":
fmt.Printf("及格
")
case grade == "F":
fmt.Printf("不及格
")
default:
fmt.Printf("差
")
}
fmt.Printf("你的等级是 %s
",grade)
}
输出结果
优秀
你的等级是 A
Type Switch语句
Type Switch语法格式
switch x.(type) {
case type:
statement(s);
case type:
statement(s);
default:
statement(s);
}
package main
import (
"fmt"
)
func main(){
var x interface{}
switch i:= x.(type) {
case nil:
fmt.Printf("x的类型 %T",i)
case int
fmt.Printf("x是int型")
case float64:
fmt.Printf("x是float64型")
case func(int) float64:
fmt.Printf("x是func(int)型")
case bool, string:
fmt.Printf("x是bool 或 string型")
default:
fmt.Printf("未知型")
}
}
输出结果
x的类型 <nil>
select语句
select是Go中的一个控制结构,类似于用于通信的switch语句.每个case必须是一个通信操作,要么是发送要么是接收.
select随机执行一个可运行的case,如果没有case可运行,它将阻塞,直到有case可运行,一个默认的子句应该是可运行的
格式
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
default:
statement(s);
}
- 每个case都必须是一个通信
- 所有的channel表达式都会被求值
- 所有被发送的表达式都会被求值
- 如果任意某个通信可以进行,它就执行,其他被忽略
- 如果有多个case都可以运行, select会随便公平地选出一个执行,其他不会执行
- 否则:
- 如果有default子句,则执行该语句
- 如果没有default子句,select将阻塞,直到某个通信可以运行,Go不会重新对channel或值进行求值
package main
import "fmt"
func main(){
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ",i1," from c1
")
case c2 <- i2:
fmt.Printf("sent ",i2," to c2
")
case i3, ok := (<-c3):
if ok{
fmt.Printf("received ",i3, "from c3
")
}else{
fmt.Printf("c3 is closed
")
}
default:
fmt.Printf("no communication
")
}
}
输出结果
no communication
Go语言循环语句
for循环
for循环是一个循环控制结构,可以执行指定次数的循环
for init; condition; post { }
for codition { }
for { }
- init : 一般为赋值表达式,给控制变量赋初值
- condition: 关系表达式或逻辑表达式,循环控制条件
- post: 一般为赋值表达式, 给控制变量增加或减量
for循环的range 格式可以对 slice, map ,数组, 字符串等进行迭代循环
for key, value := range oldMap{
newMap[key] = value
}
循环语句
Go语言允许用户在循环内使用循环
for [condition | ( init; condition; increment ) | Range]
{
for [condition | ( init; condition; increment ) | Range]
{
statement(s);
}
statement(s);
}
package main
import "fmt"
func main(){
//定义局部变量
var i,j int
for i = 2; i < 100; i++ {
for j = 2; j <= (i/j); j++{
if(i%j == 0){
break
}
}
if(j > (i/j)){
fmt.Printf("%d 是素数
",i)
}
}
}
break语句
- 用于循环语句中跳出循环, 并开始执行循环之后的语句
- break在switch(开关语句) 中在执行一条case后跳出语句的作用