Tag:
- tag并不是注释,而是用来对字段进行描述的元数据。尽管它不属于数据成员, 但却是类型的组成部分。
- 在运行期,可用反射获取标签信息。常被用作格式校验,数据库关系映射等
Tag是一个字符串,以key、value形式存在,用于标记字段说明,可以配合反射使用,以及Json解析
- key:不能为空,不能包含、空格、引号、冒号
- value:使用双引号
type User struct {name string `name:"userName"`age int `age:"userAge"`
}
获取结构体Tag内容:
type User struct {name string `name:"userName"`age int `age:"userAge"`
}func main() {u := User{}user := reflect.TypeOf(u)field := user.Field(0)fmt.Println(field.Tag.Get("name"))field2 := user.Field(1)fmt.Println(field2.Tag.Get("age"))
}
容易忽视的就是struct tag是类型的组成部分,并非数据注释那么简单
func main() {var a struct { x int `x`s string `s`}var b struct {x ints string}b = a // err:cannot use a type// struct { x int "x"; s string "s" } as type// struct { x int; s string } in assignment
}
自定义类型:
使用关键字type定义用户自定义类型,包括基于现有类型创建,或结构体、有数类型等
func main() {fmt.Println(read, exit)
}type myByte byte // 从书上看到有这个操作,但是不太理解存在的意义,其实myByte最终指向的还是byte,何必多此一举const (read myByte = iotaexit
)
多个type定义可合并成组,可在函数或代码块内定义局部类型
func main() {type (user struct { // 结构体name stringage uint}event func(string) // 函数类型)u := user{"itzhuzhu", 24}fmt.Println(u)var f event = func(s string) {fmt.Println(s)}f("haha")
}
但须注意,即便指定了基础类型,也只是表明它们拥有相同的数据结构,两者间不存在任何关系,属完全不同的两种类型。除操作符外,自定义类型不会继承基础类型的任何信息 (包括方法),不能视作别名,不能隐式转换或直接用于比较表达式。
func main() {type data intvar d data = 10var x int = d // err: cannot use d (type data) as type int in assignmentprintln(x)println(d == x) // err: invalid operation: d == x (mismatched types data and int)
}
未命名类型:
与有明确标识符的bool、int、string等类型相比array、slice、map、channel等类型与具体的元素类型或长度等属性有关,故称作未命名类型(unnamedtype)。当然,可用type为其提供具体名称以变为命名类型(namedtype)。
具有相同声明的未命名类型被视作同一类型
- 具有相同基类型的指针
- 具有相同元素类型和长度的array
- 具有相同元素类型的slice
- 具有相同键值类型的map
- 具有相同数据类型及操作方向的channel
- 具有相同字段序列(字段名、字段类型、标签以及字段顺序)的struct
- 具有相同签名(参数和返回值列表,不包括参数名)的function
- 具有相同方法集(方法名、方法签名,不包括顺序)的interface
函数的参数顺序也属于签名组成部分
func main() {var a func(int, string)var b func(string, int)b = a // err: cannot use a (type func(int, string)) as type// func(string, int) in assignmentb("s", 1)
}
未命名类型转换规则:
- 类型相同
- 基础类型相同,且其中一个是未命名类型
- 数据类型相同,将双向channe 1赋值给单向类型,且其中一个为未命名类型
- 将 nil 赋值给 s1ice、map、channel、pointer、function 以及 interface
- 实现了目标interface
func main() {type data [2]intvar d data = [2]int{1, 2} //基础类型相同,右值为未命名类型。fmt.Println(d)a := make(chan int, 2)var b chan<- int = a // chan转换为chan<-,其中b为未命名类型。b <- 2
}