程序结构
变量
- 标准语法:var 变量名字 类型 = 表达式
var i int = 1
- 简短语法:变量名字 := 表达式
j := 2
常量
- 关键字:const
- 语法:const 常量名 = 编译期确定的值
- 常量值:字符、字符串、布尔值、数值。
- 常量不能用 := 语法声明
类型
- 语法:type 类型名字 底层类型
type Person struct {
name string
age int
}
控制语句
for
Go中唯一的循环结构
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
if-else
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
- 特点:可以在条件表达式前执行一个简单的语句
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
switch-case
- 只执行匹配的case(Go自动加了break语句)
- case 无需为常量,且取值不必为整数
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.\n", os)
}
defer
- defer 语句会将函数推迟到外层函数返回之后执行。
- 推迟的函数调用会被压入一个栈中,按照后进先出的顺序调用。
defer fmt.Println("world")
fmt.Println("hello")
包和文件
- 文件:组织Go代码
- 包:管理Go文件,支持模块化,独立命名空间
- 导出规则:如果一个名字是大写字母开头的,那么该名字是导出的,包外可访问
- 匿名导入:它会计算包级变量的初始化表达式和执行导入包的init初始化函数
基础数据类型
整型
- 有符号整数:int8、int16、int32、int64、int、rune
- 无符号整数:uint8、uint16、uint32、uint64、uint、uintptr、byte
- int、uint、uintptr:在32位系统上是32位,在64位系统上是64位
- byte:等同于uint8,表示一个字节
- rune:等同于int32,表示一个Unicode码点
浮点型
- 浮点数:float32、float64
- 复数:complex64、complex128
布尔型
bool:true、false
字符串
- string:默认使用UTF8编码
- 常用包:bytes、strings、strconv、unicode
零值
声明但未初始化的变量会被赋予零值
- 数值类型:0
- 布尔类型:false
- 字符串:""
var i int
var b bool
var s string
fmt.Printf("%v %v %q\n", i, b, s) // 0 false ""
类型转换
表达式 T(v) 将值 v 转换为类型 T
i := 42
f := float64(i)
u := uint(f)
复合数据类型
数组
- 声明:var a [3]int
- 初始化:var q [3]int = [3]int{1, 2, 3}
- 简短写法:a := [3]int{1, 2, 3}
切片
- 声明:var s []int
- 添加元素:s = append(s, 1, 2, 3)
- 切片操作:s[i:j],表示s的从第i个元素开始到第j-1个元素的子序列。
- 切片的长度:它所包含的元素个数,len(s)
- 切片的容量:从它的第一个元素开始数,到其底层数组元素末尾的个数,cap(s)
- 切片的零值:nil
哈希表
- 创建
// m1 = nil
m1 := make(map[string]int)
// m2 = {}
m2 := map[string]int{}
// m3 = {"age":18}
m2 := map[string]int{
"age": 18,
}
- 读写
m[key] = elem // 新增或更新
elem = m[key] // 获取
delete(m, key) // 删除
elem, ok := m[key] // 判断键是否存在
结构体
- 定义
type Employee struct {
ID int
Name string
}
- 初始化
e := Employee{
ID: 123,
Name: "test",
}
- JSON序列化
type Employee struct {
ID int `json:"id"`
Name string `json:"name"`
}
data, err := json.Marshal(e)
if err != nil {
log.Fatalf("JSON marshaling failed: %v", err)
}
fmt.Printf("%s\n", data)
range
// 遍历数组
for index, value := range array {
fmt.Printf("%d %d\n", index, value)
}
// 忽略index
for _, value := range array {
fmt.Printf("%d\n", value)
}
// 忽略value
for index := range array {
fmt.Printf("%d\n", index)
}
// 遍历哈希表
for key, value := range map {
fmt.Printf("%d %d\n", key, value)
}
函数
声明
func name(parameter-list) (result-list) {
body
}
func add(x int, y int) int {
return x + y
}
// 如果连续参数类型相同,可以简写为:
func add(x, y int) int {
return x + y
}
多返回值
在Go中,函数可以返回任意数量的返回值。
func swap(x, y string) (string, string) {
return y, x
}
方法
声明
方法就是一类带特殊的接收者参数的函数。
// 方式1:值类型
func (t T) name(parameter-list) (result-list) {
body
}
// 方式2:指针类型
func (t *T) name(parameter-list) (result-list) {
body
}
方式1和方式2的区别:调用方法时,前者是深拷贝,后者是浅拷贝。
封装
type Counter struct { n int }
func (c *Counter) N() int { return c.n }
func (c *Counter) Increment() { c.n++ }
func (c *Counter) Reset() { c.n = 0 }
接口
声明
type error interface {
Error() string
}
实现
隐式实现:一个类型拥有某接口的所有方法,则该类型就实现了这个接口。
// errorString类型
type errorString struct {
text string
}
// 实现error接口
func (e *errorString) Error() string {
return e.text
}
使用
func New(text string) error {
return &errorString{text}
}
空接口
- 形式:
interface{}
- 空接口可保存任何类型的值。
- 空接口被用来处理未知类型的值。
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
func main() {
var i interface{}
describe(i) // (, )
i = 42
describe(i) // (42, int)
i = "hello"
describe(i) // (hello, string)
}
类型断言
- 类型断言:提供了访问接口值底层具体值的方式。
-
t := i.(T)
:断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t。若 i 并未保存 T 类型的值,则会触发panic异常。 -
t, ok := i.(T)
判断接口值 i 是否保存了具体类型 T,如果为true,那么 t 将会是其底层值,否则而 t 将为 T 类型的零值。不会触发panic异常。
类型选择
- 类型选择:一种按顺序从几个类型断言中选择分支的结构。
switch v := i.(type) {
case T:
// v 的类型为 T
case S:
// v 的类型为 S
default:
// 没有匹配,v 与 i 的类型相同
}
本文由mdnice多平台发布