func main() {
s := "中.国"
println(len(s), utf8.RuneCountInString(s))
}
5.2 数组
func main() {
var d1 [3]int
var d2 [2]int
d1 = d2 //错误:cannot use d2(type [2]int) as type [3]int in assignment
var a [4]int //元素自动初始化为零
b := [4]int{2, 5} //未提供初始值的元素自动初始化为0
c := [4]int{5, 3: 10} //可指定索引位置初始化
d := [...]int{1,2,3} //编译器按初始化值数量确定数组长度
e := [...]int{10, 3: 100} //支持索引初始化,但注意数组长度与此有关
fmt.Println(a,b,c,d,e)
}
对于结构等复合类型,可省略元素初始化类型标签
func main() {
type user struct {
name string
age byte
}
d := [...]user{
{"Tom", 20},
{"Mary", 18},
}
fmt.Printf("%#v\n", d)
}
在定义多维数组时,仅第一维允许使用”…”
内置函数len和cap都返回第一维度长度
如元素类型支持==, != 操作符,那么数组也支持此操作
func main() {
var a, b [2]int
println(a == b)
c := [2]int{1, 2}
d := [2]int{0, 1}
println(c != d)
var e, f [2]map[string]int
println(e == f) //invalid operation: e == f ([2]map[string]int cannot be compared)
}
指针数组是指元素为指针类型的数组,数组指针是获取数组变量的地址
func main() {
x, y := 10, 20
a := [...]*int{&x, &y} //元素为指针的指针数组
p := &a // 存储数组地址的指针
fmt.Printf("%T, %v\n", a, a)
fmt.Printf("%T, %v\n", p, p)
}
func main() {
m := make(map[string]int)
m["a"] = 1
m["b"] = 2
m2 := map[int] struct {
x int
}{
1: {x:100},
2: {x:200},
}
fmt.Println(m, m2)
}
字典被设计成”not addressable”,故不能直接修改value成员(结构或数组)
func main() {
type user struct {
name string
age byte
}
m := map[int]user{
1: {"Tom", 19},
}
m[1].age += 1 //错误: cannot assign to struct field m[1].age in map
}
type node struct {
_ int
id int
next *node
}
func main() {
n1 := node{
id:1,
}
n2 := node {
id:2,
next:&n1,
}
fmt.Println(n1, n2)
}
使用命名方式初始化指定字段
func main() {
type user struct {
name string
age byte
}
u1 := user{"Tom", 12}
u2 := user{"Tom"} //错误: too few values in struct initializer
fmt.Println(u1, u2)
}
func main() {
u := struct { //直接定义匿名结构变量
name string
age byte
}{
name:"Tom",
age:12,
}
type file struct {
name string
attr struct { //定义匿名结构类型字段
owner int
perm int
}
}
f := file {
name:"test.dat",
/*attr:{ //错误missing type in composite literal
owner:1,
perm:0755,
},*/
}
f.attr.owner = 1 //正确方式
f.attr.perm = 0755
fmt.Println(u, f)
}
只有在所有字段类型全部支持时,才可做相等操作
func main() {
type data struct {
x int
y map[string]int
}
d1 := data{
x:100,
}
d2 := data{
x:100,
}
println(d1 == d2) //无效操作,struct containing map[string]int cannot be compared
}
可使用指针直接操作结构字段,但不能是多级指针
func main() {
type user struct {
name string
age int
}
p := &user{
name:"Tom",
age:20,
}
p.name = "Mary"
p.age++
p2 := &p
*p2.name = "Jack" //错误p2.name undefined(type **user has no field or method name)
}
type file struct {
name string
}
type data struct {
file
name string //与匿名字段file.name重名
}
func main() {
d := data{
name:"data",
file:file{"file"},
}
d.name = "data2" //访问data.name
d.file.name = "file2" //使用显式字段名访问data.file.name
fmt.Println(d.name,d.file.name)
}
如果多个相同层级的匿名字段成员重名,就只能使用显式字段名访问,因为编译器无法确定目标
type file struct {
name string
}
type log struct {
name string
}
type data struct {
file
log
}
func main() {
d := data{}
d.name = "name" //错误: ambiguous selector d.name
d.file.name = "file"
d.log.name = "log"
}
字段标签(tag)并不是注释,而是用来对字段进行描述的元数据。
在运行期,可用反射获取标签信息。它常被用作格式校验,数据库关系映射等。
import (
"fmt"
"reflect"
)
type user struct {
name string `昵称`
sex byte `性别`
}
func main() {
u := user{"Tome",1}
v := reflect.ValueOf(u)
t := v.Type()
for i, n :=0, t.NumField(); i<n; i++ {
fmt.Printf("%s:%v\n", t.Field(i).Tag, v.Field(i))
}
}
/**
昵称:Tome
性别:1
**/