package main
import (
"fmt"
)
func main() {
fmt.Printf("%T", nil) // .\main.go:9:10: use of untyped nil
print(nil)
}
引用类型的零值(初始值)都是nil
package main
import (
"fmt"
)
func main() {
var m map[int]string
var ptr *int
var c chan int
var sl []int
var f func()
var i interface{}
fmt.Printf("%#v\n", m) // map[int]string(nil)
fmt.Printf("%#v\n", ptr) // (*int)(nil)
fmt.Printf("%#v\n", c) // (chan int)(nil)
fmt.Printf("%#v\n", sl) // []int(nil)
fmt.Printf("%#v\n", f) // (func())(nil)
fmt.Printf("%#v\n", i) // <nil>
}
不同引用类型的nil值,指针是相同的
package main
import (
"fmt"
)
func main() {
var arr []int
var num *int
fmt.Printf("%p\n", arr) // 0x0
fmt.Printf("%p", num) // 0x0
}
不同引用类型的nil值,占用大小不同
package main
import (
"fmt"
"unsafe"
)
func main() {
var p *struct{}
fmt.Println( unsafe.Sizeof( p ) ) // 8
var s []int
fmt.Println( unsafe.Sizeof( s ) ) // 24
var m map[int]bool
fmt.Println( unsafe.Sizeof( m ) ) // 8
var c chan string
fmt.Println( unsafe.Sizeof( c ) ) // 8
var f func()
fmt.Println( unsafe.Sizeof( f ) ) // 8
var i interface{}
fmt.Println( unsafe.Sizeof( i ) ) // 16
}
package main
import (
"fmt"
)
func main() {
// 不同类型变量
var m map[int]string
var ptr *int
fmt.Printf(m == ptr) // invalid operation: arr == ptr (mismatched types []int and *int)
}
package main
import (
"fmt"
)
func main() {
// 相同类型变量
var s1 []int
var s2 []int
fmt.Printf(s1 == s2) // invalid operation: s1 == s2 (slice can only be compared to nil)
}
变量(有可能是nil 或者 非nil)可以与nil值比较:
package main
import (
"fmt"
)
func main() {
var s1 []int
fmt.Println(s1 == nil) // true
}
基本数据类型
数值型
整型
无符号整型
数据类型
存储空间(字节)
值范围
数据级别
默认值
uint8
1
0 ~ 255
百
0
uint16
2
0 ~65535
6万多
0
uint32
3
0 ~ 4294967295
40多亿
0
uint64
4
0 ~ 18446744073709551615
大到没有概念
0
uint
系统决定,无符号整型
32位系统位int32,64位系统位int64
0
var ui2 uint8 = 1
fmt.Printf("类型 uint8, 长度=%d字节 \n", unsafe.Sizeof(ui2))
var ui3 uint16 = 1
fmt.Printf("类型 uint16, 长度=%d字节 \n", unsafe.Sizeof(ui3))
var ui4 uint32 = 1
fmt.Printf("类型 uint32, 长度=%d字节 \n", unsafe.Sizeof(ui4))
var ui5 uint64 = 1
fmt.Printf("类型 uint64, 长度=%d字节 \n", unsafe.Sizeof(ui5))
有符号整型
数据类型
存储空间(字节)
值范围
数据级别
默认值
int8
1
-128 ~ 127
正负百
0
int16
2
-32768 ~ 32767
正负3万多
0
int32
3
-2147483648 ~ 2147483647
正负大20多亿
0
int64
4
-9223372036854775808 ~ 9223372036854775807
正负大到没有概念
0
int
系统决定,有符号整型
32位系统位int32,64位系统位int64
0
var i2 int8 = 1
fmt.Printf("类型 int8, 长度=%d字节 \n", unsafe.Sizeof(i2))
var i3 int16 = 1
fmt.Printf("类型 int16, 长度=%d字节 \n", unsafe.Sizeof(i3))
var i4 int32 = 1
fmt.Printf("类型 int32, 长度=%d字节 \n", unsafe.Sizeof(i4))
var i5 int64 = 1
fmt.Printf("类型 int64, 长度=%d字节 \n", unsafe.Sizeof(i5))
字符整型
数据类型
存储空间(字节)
作用
byte
uint8的别名
用与表示一个ASCII
rune
int32的别名
用于表示一个Unicode代码点
// 获取对应字符的ASCII码值
var a byte = 'a'
fmt.Println(a)
// 将字符串转换为Unicode码点
first := "Hello, 世界"
fmt.Println([]rune(first))
表示一个ASCII:
var ch byte = 65
var ch byte = '\x41' // 16进制
var ch byte = 'A'
var a string = "Hello 世界"
fmt.Printf("%c \n", []byte(a)[0]) // H
fmt.Printf("%c \n", []rune(a)[7]) // 界
字符拼接 "+"
fmt.Println("a" + "b") // 注意,其他类型不会进行字符串转换
多行字符串
多行字符串中的内容都会原样输出,转义字符不会生效。通常用语内嵌代码或者数据
const str = `第一行
第二\n行
第三行`
fmt.Println(str)
输出结果为:
第一行
第二\n行
第三行
类型转换
数值类型相互转换
// GO语言数据类型转换,只有显示转换(强制类型转换),没有隐式转换
fmt.Println("----------- 基本数据类型互相转换 -------------")
var i int = 100
var f float32 = float32(i)
fmt.Println(f)
// 注意,将大范围值转换为小范围值,可能会造成数据损失
var i1 int64 = 8888
var i2 int8 = int8(i1)
fmt.Println(i2)
// 赋值左右数据类型一致,否则会报错
var n1 int32 = 12
var n2 int64 = int64(n1) + 31
fmt.Println(n2)
scene := make(map[string]int)
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
for k, v := range scene {
fmt.Println(k, v)
}
添加/更新键值对
scene["china"] = 960
删除键值对: delete()
scene := make(map[string]int)
// 准备map数据
scene["route"] = 66
scene["brazil"] = 4
scene["china"] = 960
delete(scene, "brazil")
for k, v := range scene {
fmt.Println(k, v)
}
清空map
go没有提供清空map的方法,有两种方法可以清空map:
遍历调用delete()
给变量重新赋予一个新创建的map
结构体
结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。
定义结构体
type 类型名 struct {
字段1 字段1类型
字段2 字段2类型
…
}
type用于自定义类型,定义type可以对结构体进行复用
type Point struct {
X int
Y int
}
同类型变量可将字段放在一行
type Color struct {
R, G, B byte
}
空结构体,没有意义
type Ept struct {}
字段类型不受限制
结构体的字段类型不受限制,可以是基本类型,也可以是复合类型,比如函数等:
// Go program to illustrate the function
// as a field in Go structure
package main
import "fmt"
// Finalsalary of function type
type Finalsalary func(int, int) int
// Creating structure
type Author struct {
name string
language string
Marticles int
Pay int
// Function as a field
salary Finalsalary
}
// Main method
func main() {
// Initializing the fields
// of the structure
result := Author{
name: "Sonia",
language: "Java",
Marticles: 120,
Pay: 500,
salary: func(Ma int, pay int) int {
return Ma * pay
},
}
// Display values
fmt.Println("Author's Name: ", result.name)
fmt.Println("Language: ", result.language)
fmt.Println("Total number of articles published in May: ", result.Marticles)
fmt.Println("Per article pay: ", result.Pay)
fmt.Println("Total salary: ", result.salary(result.Marticles, result.Pay))
}
实例化结构体
基本实例化形式
type Point struct {
X int
Y int
}
var p Point
p.X = 10
p.Y = 20
实例化指针类型结构体(常用)
type Player struct{
Name string
HealthPoint int
MagicPoint int
}
tank := new(Player)
tank.Name = "Canon"
tank.HealthPoint = 300
取地址符的实例化(常用)
对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作
type Command struct {
Name string // 指令名称
Var *int // 指令绑定的变量
Comment string // 指令的注释
}
var version int = 1
cmd := &Command{}
cmd.Name = "version"
cmd.Var = &version
cmd.Comment = "show version"
初始化结构体
键值类型初始化
type People struct {
name string
child *People
}
relation := &People{
name: "爷爷",
child: &People{
name: "爸爸",
child: &People{
name: "我",
},
},
}
多值列表初始化
字段顺序要保持一致
所有字段必须要初始化
package main
import _ "fmt"
func main() {
type People struct {
name string
child *People
}
relation := &People{
"爷爷",
&People{
"爸爸",
&People{
name: "我",
},
},
}
}
匿名结构体的初始化
package main
import (
"fmt"
)
// 打印消息类型, 传入匿名结构体
func printMsgType(msg *struct {
id int
data string
}) {
// 使用动词%T打印msg的类型
fmt.Printf("%T\n", msg)
}
func main() {
// 实例化一个匿名结构体
msg := &struct { // 定义部分
id int
data string
}{ // 值初始化部分
1024,
"hello",
}
printMsgType(msg)
}
管道
参见:并发编程/channel
函数
接口
参照:面向对象/接口
类型定义
// 定义了一个person类型,
type Person struct {
Name string
Age int
}
// Go1.9之前,类型byte、rune通过自定义类型定义
type byte uint8
type rune int32
// Go1.9 之后,类型byte、rune则通过类型别名定义
type byte = uint8
type rune = int32
定义类型别名:
// 类型别名定义的格式:
type TypeAlias = Type
// 根据内置类型创建类型别名
type myInt = int64
// 根据自定义类型创建类型别名
type myDuration = time.Duration
// 根据其他类型别名创建类型别名
type myInt2 = myInt