1、Go 内置数据类型
在 Go 中,为了更合理利用内存、提高类型安全,我们会为变量指定具体的类型。常见内置类型可以大致分为:
1)基本数据类型
整型:
int,int8,int16,int32,int64无符号整型:
uint,uint8(别名byte),uint16,uint32,uint64浮点型:
float32,float64复数型:
complex64,complex128布尔型:
bool(值为true/false)字符串:
string字符(Unicode 码点):
rune(本质是int32)
2)聚合类型
数组:
[N]T固定长度切片:
[]T动态长度,最常用的“数组”类型结构体:
struct { ... }组合多个字段
3)引用 / 复合类型
映射(字典):
map[K]V指针:
*T函数类型:
func(...) ...接口类型:
interface{...}通道:
chan T
4)特殊零值 / nil
nil:指针、切片、map、chan、函数、接口等的“空值”
类似 Python 的None,表示“没有指向任何东西”。
2、使用 %T 或 reflect 获取变量类型
Go 中可以通过 fmt.Printf 或 reflect.TypeOf 来查看变量的类型。
package main
import (
"fmt"
"reflect"
)
func main() {
x := 5
fmt.Printf("类型: %T\n", x) // int
fmt.Println("类型:", reflect.TypeOf(x)) // int
fmt.Printf("%T\n", "Hello")
fmt.Printf("%T\n", 3)
fmt.Printf("%T\n", 3.14)
fmt.Printf("%T\n", 1+2i)
fmt.Printf("%T\n", []string{"c", "java", "python"})
fmt.Printf("%T\n", [3]string{"c", "java", "python"}) // 数组
fmt.Printf("%T\n", map[string]int{"age": 12})
fmt.Printf("%T\n", true)
fmt.Printf("%T\n", byte(5))
}
3、定义变量并指定数据类型
在 Go 中,给变量赋值时,就确定了它的类型(但不能随意改成其他类型)。可以显式写类型,也可以让编译器推断。
package main
import "fmt"
func main() {
var s string = "Hello World" // string
var i int = 20 // int
var f float64 = 20.5 // float64
var c complex128 = 1 + 2i // complex128
nums := []string{"c", "python", "java"} // 切片 slice
tupleLike := [3]string{"c", "python", "java"} // 数组 array
r := []int{0, 1, 2, 3, 4, 5} // 当作“range”生成的切片
m := map[string]int{"age": 20} // map
setLike := map[string]struct{}{ // 集合一般用 map 实现
"c": {},
"python": {},
"java": {},
}
fs := map[string]bool{"c": true, "python": true} // 另一种简单集合
b := true // bool
by := []byte("Hello") // []byte,相当于 Python 的 bytes
fmt.Println(s, i, f, c, nums, tupleLike, r, m, setLike, fs, b, by)
}
注意:
Go 没有 list/tuple/dict/set 这些名字,但切片 []T + map[K]V 能覆盖大部分场景。
Go 变量一旦确定类型,就不能随便换成其他类型(需要转换或新建变量)。
4、通过“构造函数式”写法指定类型(类型转换/创建)
Python 用 int(), float(), list() 等构造函数。
Go 中对应的是 类型转换 和 内建函数。
常见写法:
package main
import "fmt"
func main() {
// 基本类型转换
var s string = "Hello World" // string
var i int = int(20) // int
var f float64 = float64(20.5) // float64
var c complex128 = complex(0, 1) // complex128 (0+1i)
// 切片 & 数组
arr := [3]string{"c", "python", "java"} // 数组
sl := []string{"c", "python", "java"} // 切片
// map(类似 dict)
m := map[string]interface{}{
"name": "cjavapy",
"age": 3,
}
// “set” 一般用 map 实现
set := map[string]struct{}{"c": {}, "java": {}, "python": {}}
// bool 转换(非 0 即 true)
b := bool(5 != 0) // 手动写逻辑,而不是 bool(5) 这种 Python 写法
// bytes:常用 []byte
bytes := make([]byte, 5) // 长度为 5 的字节切片,默认全 0
fmt.Println(s, i, f, c, arr, sl, m, set, b, bytes)
}
Go 中没有像 bool(5) 这样的隐式转换,必须自己写逻辑决定 true/false。
5、nil:Go 里的“空值”
在 Python 中有 NoneType / None。
在 Go 中,则是 nil——适用于指针、切片、map、chan、函数、接口等类型。
1)nil 示例
package main
import "fmt"
func main() {
var p *int // 指针,默认是 nil
var s []int // 切片 nil
var m map[string]int // map nil
var ch chan int // 通道 nil
fmt.Println(p == nil) // true
fmt.Println(s == nil) // true
fmt.Println(m == nil) // true
fmt.Println(ch == nil) // true
// 使用前记得初始化
s = make([]int, 0)
m = make(map[string]int)
ch = make(chan int)
fmt.Println(s == nil) // false
fmt.Println(m == nil) // false
}
2)函数返回值“空”场景
类似 Python 返回 None 的场景,在 Go 中常用 零值或 nil 表示,
package main
import "fmt"
func exampleFunction() error {
fmt.Println("这是一个示例函数")
return nil // 没有错误
}
func main() {
err := exampleFunction()
if err == nil {
fmt.Println("result is nil (无错误)")
}
}
6、Go 常用数据类型综合示例
package main
import (
"fmt"
"sort"
)
func main() {
// 1) 切片:购物清单
shoplist := []string{"apple", "mango", "carrot", "banana"}
fmt.Println("我有", len(shoplist), "样物品要购买。")
fmt.Print("这些物品是:")
for _, item := range shoplist {
fmt.Print(item, " ")
}
fmt.Println()
fmt.Println("我还需要买米。")
shoplist = append(shoplist, "rice")
fmt.Println("我的购物清单现在是", shoplist)
fmt.Println("我现在要对购物清单进行排序")
sort.Strings(shoplist)
fmt.Println("排序后的购物清单是", shoplist)
fmt.Println("我将购买的第一样物品是", shoplist[0])
olditem := shoplist[0]
shoplist = shoplist[1:] // 删除第 0 项
fmt.Println("我买了", olditem)
fmt.Println("我的购物清单现在是", shoplist)
// 2) 数组 & 嵌套:动物园
zoo := [3]string{"python", "elephant", "penguin"}
fmt.Println("动物园里有", len(zoo), "种动物")
newZoo := [][]string{
{"monkey"},
{"camel"},
zoo[:], // 把数组转成切片挂进来
}
fmt.Println("新动物园里有", len(newZoo), "个笼子")
fmt.Println("新动物园里的所有动物有", newZoo)
fmt.Println("从旧动物园带来的动物有", newZoo[2])
fmt.Println("从旧动物园带来的最后一只动物是", newZoo[2][2])
total := len(newZoo) - 1 + len(newZoo[2])
fmt.Println("新动物园里的动物总数是", total)
// 3) map:通讯录
ab := map[string]string{
"Swaroop": "Swaroop@Swaroopch.com",
"Larry": "larry@wall.org",
"Matsumoto": "matz@ruby-lang.org",
"Spammer": "spammer@hotmail.com",
}
fmt.Println("Swaroop 的地址是", ab["Swaroop"])
delete(ab, "Spammer")
fmt.Printf("\n通讯录中有 %d 个联系人\n\n", len(ab))
for name, address := range ab {
fmt.Printf("联系 %s 的地址是 %s\n", name, address)
}
ab["Guido"] = "guido@python.org"
if addr, ok := ab["Guido"]; ok {
fmt.Println("\nGuido 的地址是", addr)
}
// 4) 切片 & 字符串索引 / 切片
name := "Swaroop"
fmt.Println("第0项是", shoplist[0])
fmt.Println("第1项是", shoplist[1])
fmt.Println("第2项是", shoplist[2])
fmt.Println("倒数第1项是", shoplist[len(shoplist)-1])
fmt.Println("倒数第2项是", shoplist[len(shoplist)-2])
fmt.Println("第0个字符是", string(name[0])) // 注意:name[i] 是 byte,需要转 string
fmt.Println("第1到3项是", shoplist[1:3])
fmt.Println("第2项到最后是", shoplist[2:])
fmt.Println("第1项到倒数第1项是", shoplist[1:len(shoplist)-1])
fmt.Println("从头到尾所有项是", shoplist[:])
fmt.Println("第1到3个字符是", name[1:3]) // 字符串切片按字节
fmt.Println("第2个字符到最后是", name[2:])
fmt.Println("第1个字符到倒数第1个字符是", name[1:len(name)-1])
fmt.Println("从头到尾所有字符是", name[:])
// 5) set:用 map 实现
bri := map[string]struct{}{
"brazil": {},
"russia": {},
"India": {},
"China": {},
}
_, exists := bri["India"]
fmt.Println("India 在 bri 中吗?", exists)
}
Go 字符串是 UTF-8 编码,s[i] 取的是 字节,中文会占多个字节,做“按字符”切片时要用 []rune。