Go语言也称为 Golang,是由 Google 公司开发的一种静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言。
Go语言(或 Golang)起源于 2007 年,并在 2009 年正式对外发布。Go 是非常年轻的一门语言,它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。
Go语言是编程语言设计的又一次尝试,是对类C语言的重大改进,它不但能让你访问底层操作系统,还提供了强大的网络编程和并发编程支持。Go语言的用途众多,可以进行网络编程、系统编程、并发编程、分布式编程。
Go语言的推出,旨在不损失应用程序性能的情况下降低代码的复杂性,具有“部署简单、并发性好、语言设计良好、执行性能好”等优势,目前国内诸多 IT 公司均已采用Go语言开发项目。
Go语言有时候被描述为“C 类似语言”,或者是“21 世纪的C语言”。Go 从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有C语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。
因为Go语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口(interface)的概念来实现多态性。Go语言有一个清晰易懂的轻量级类型系统,在类型之间也没有层级之说。因此可以说Go语言是一门混合型的语言。
Go 语言按类别有以下几种数据类型:
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。
整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
整型
1 uint8:无符号 8 位整型 (0 到 255)
2 uint16:无符号 16 位整型 (0 到 65535)
3 uint32:无符号 32 位整型 (0 到 4294967295)
4 uint64:无符号 64 位整型 (0 到 18446744073709551615)
5 int8:有符号 8 位整型 (-128 到 127)
6 int16:有符号 16 位整型 (-32768 到 32767)
7 int32:有符号 32 位整型 (-2147483648 到 2147483647)
8 int64:有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
浮点型
1 float32:IEEE-754 32位浮点型数
2 float64:IEEE-754 64位浮点型数
3 complex64:32 位实数和虚数
4 complex128:64 位实数和虚数
其他数字类型
1 byte:类似 uint8
2 rune:类似 int32
3 uint:32 或 64 位
4 int:与 uint 一样大小
5 uintptr:无符号整型,用于存放一个指针
字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
(a) 指针类型(Pointer)
(b) 数组类型
© 结构化类型(struct)
(d) Channel 类型
(e) 函数类型
(f) 切片类型
(g) 接口类型(interface)
(h) Map 类型
注意⚠️
go的所有类型都没有隐式转换,只能自己手动转换;如:
var a int8 = 6
var b int32
b = a // 编译错误
b = int32(a)
Go语言的变量声明的标准格式为:以关键字 var 开头,后置变量类型,行尾无须分号。
var 变量名 变量类型
var a int
var b string = “hello word”
觉得每行都用 var 声明变量比较烦琐?没关系,还有一种为懒人提供的定义变量的方法:使用关键字 var 和括号,可以将一组变量定义放在一起。
var (
a int
b string
c []float32
d func() bool
e struct {
x int
}
)
除 var 关键字外,还可使用更加简短的变量定义和初始化语法。
名字 := 表达式
c,d := 1,“hello”
需要注意的是,简短模式(short variable declaration)有以下限制:
定义变量,同时显式初始化;不能提供数据类型;只能用在函数内部。
常量的定义格式:
const identifier [type] = value
你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
显式类型定义: const a string = "abc"
隐式类型定义: const b = "abc"
多个相同类型的声明可以简写为:
const c1, c2 = v1, v2
更多的时候,我们采用下面的方式定义多个常量
const (
a = 1
b = 2
)
iota 常量生成器
在go中常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加一。
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = iota //5,恢复计数
g //6
)
比如我们定义星期的常量:周日将对应 0,周一为 1,以此类推。
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
还可以用它定义一些移位操作,如
const (
B = 1 << (10 * iota)
KB
GB
TB
PB
)
在语言中没有while循环,因为可以直接用for循环实现。Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
// 一般的 for :
for init; condition; post { }
// 和 while 一样:
for condition { }
// 和 while(true) 一样:
for { }
init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。
For-each range 循环
这种格式的循环可以对 slice、map、数组、字符串等进行迭代循环。
for key, value := range oldMap {
newMap[key] = value
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
if 语句
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
var age int = 16
if age < 0 || age > 130 {
fmt.Println("非法")
} else if age < 18 {
fmt.Println("未成年")
} else {
fmt.Println("成年")
}
go这里的条件语句还可以使用分号,非常实用。如:
if data,err := service函数; err !=nil {
fmt.Printf("执行业务逻辑失败" );
} else {
fmt.Printf("执行业务逻辑成功,执行结果数据:%s", data);
}
switch 语句
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。但是相比于其他的语言,比如Java不同的是:
switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。
var a = "hello"
switch a {
case "hello":
fmt.Println(1)
case "world":
fmt.Println(2)
case "hi", "you":
fmt.Println(3)
default:
fmt.Println(0)
}
var grade string = "B"
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
select 语句
select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。
每个 case 都必须是一个通信
所有 channel 表达式都会被求值
所有被发送的表达式都会被求值
如果任意某个通信可以进行,它就执行,其他被忽略。
如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
否则:如果有 default 子句,则执行该语句; 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}