以不同的方式组合基本类型可以构造出来的复合数据类型。
数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。
数组定义为:[...]T ,方括号内为数组长度
//数组的定义及初始化
var a [3]int
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2}
q := [...]int{1, 2, 3} //... 表示数组的长度是根据初始化值的个数来计算的
Slice
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T 代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。
//slice的定义及初始化
months := [...]string{1: "January", /* ... */, 12: "December"} //数组
Q2 := months[4:7]
summer := months[6:9]
fmt.Println(Q2) // ["April" "May" "June"]
fmt.Println(summer) // ["June" "July" "August"]
append函数
内置的append函数用于向slice追加元素
var runes []rune
for _, r := range "Hello, 世界" {
runes = append(runes, r)
}
Map
哈希表是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同 的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。
Map的定义:map[K]V
//Map的定义及初始化
ages := make(map[string]int) // mapping from strings to ints
ages := map[string]int{
"alice": 31,
"charlie": 34,
}
ages["alice"] = 32
fmt.Println(ages["alice"]) // "32"
delete(ages, "alice") // remove element ages["alice"]
结构体
结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员。
//结构体的定义及初始化
type Employee struct {
ID int
Name string
DoB time.Time
Position string
Salary int
ManagerID int
}
var dilbert Employee
dilbert.Salary -= 5000 // demoted, for writing too few lines of code
//通过对成员取址,通过指针访问
position := &dilbert.Position
*position = "Senior " + *position // promoted, for outsourcing to Elbonia
结构体面值
结构体值也可以用结构体面值表示,结构体面值可以指定每个成员的值。
type Point struct{ X, Y int }
p := Point{1, 2}
q := Point{X: 1, Y: 2}//推荐
结构体比较
如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用 ==或!=运算符进行比较。
可比较的结构体类型和其他可比较的类型一样,可以用于map的key类型。
type Point struct{ X, Y int }
p := Point{1, 2}
q := Point{2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q) // "false"
结构体嵌入和匿名成员
只声明一个成员对应的数据类型而不指名成员的名字;这类成员就叫匿名成 员。匿名成员的数据类型必须是命名的类型或指向一个命名的类型的指针。
type Point struct {
X, Y int
}
type Circle struct {
Center Point
Radius int
}
//结构体嵌入
type Wheel struct {
Circle Circle
Spokes int
}
var w Wheel
w.Circle.Center.X = 8
//匿名成员
w.X = 8 // equivalent to w.circle.point.X = 8
JSON
JSON是对JavaScript中各种类型的值——字符串、数字、布尔值和对象——Unicode本文编码。它可以用 有效可读的方式表示第三章的基础数据类型和本章的数组、slice、结构体和map等聚合数据类型。
将结构体转为JSON的过程叫编组(marshaling)。编组通过调用json.Marshal函数完成
data, err := json.Marshal(movies)
编码的逆操作是解码,对应将JSON数据解码为Go语言的数据结构,Go语言中一般叫unmarshaling,通过 json.Unmarshal函数完成。
var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
文本和模板
有时候会需要复杂的打印格式,这 时候一般需要将格式化代码分离出来以便更安全地修改。这写功能是由text/template和html/template 等模板包提供的,它们提供了一个将变量值填充到一个文本或HTML格式的模板的机制。
一个模板是一个字符串或一个文件,里面包含了一个或多个由双花括号包含的{{action}}对象。
模板定义:
const templ = `{{.TotalCount}} issues:
{{range .Items}}----------------------------------------
Number: {{.Number}}
User: {{.User.Login}}
Title: {{.Title | printf "%.64s"}}
Age: {{.CreatedAt | daysAgo}} days
{{end}}`
func daysAgo(t time.Time) int {
return int(time.Since(t).Hours() / 24)
}
生成模板的输出需要两个处理步骤。第一步是要分析模板并转为内部表示,然后基于指定的输入执行模板。分析模板部分一般只需要执行一次。下面的代码创建并分析上面定义的模板templ。注意方法调用链 的顺序:template.New先创建并返回一个模板;Funcs方法将daysAgo等自定义函数注册到模板中,并返回模板;最后调用Parse函数分析模板。
report, err := template.New("report").
Funcs(template.FuncMap{"daysAgo": daysAgo}).
Parse(templ)
if err != nil {
log.Fatal(err)
}
//或者,如下简化
var report = template.Must(template.New("issuelist").
Funcs(template.FuncMap{"daysAgo": daysAgo}).
Parse(templ))
总结
整体介绍了go语言的符合数据类型,深入学习需自己多实践摸索