go 复合类型: 数组、slice、map、结构体
一、数组
数组是具有固定长度且拥有零个或多个相同数据类型元素的序列。
声明数组:
var a [3]int // 默认情况下一个数组中的元素初始值为元素类型的零值, 对于Int是0
fmt.Println(a[0]) // 输出0
初始化数组:
var q [3]int = [3]Int{1,2,3} // 数组字面量初始化
var r [3]int // 先声明 ,后初始化
r[0] = 1
r[1] = 2
x := [...]int{1,2,3} // 长度为初始化元素个数
y := [...]int{99: -1} // 定义一个拥有100个元素的数组,并且出最后一个元素为-1外,其它元素都为0
使用数组:
fmt.Println(a[0]) // 输出第一个元素
// 输出索引和元素
for i,v := range a {
fmt.Printf("%d %d\n", i,v)
}
// 仅输出元素
for _,v := range a {
fmt.Printf("%d\n", v)
}
// 获取数组长度
fmt.Printf("%d\n", len(a))
二、切片(slice)
slice是表示一个拥有相同类型元素的可变长度的序列,通常写成[]T。可以用来访问数组的部分或全部元素,这个数组称为slice的底层数组,slice有三个属性:指针、长度、容量。指针指向数组的第一个可以从slice中访问的元素,长度是指slice中元素的个数,它不能超过slice的容量。容量是指slice的起始元素到底层数组的最后一个元素之间的个数。slice的零值是nil。
创建slice:
// 创建一个底层数组
week := [...]string{"Monday", "Tuesday","Wednesday","Thursday","Friday","Saturday ","Sunday"}
// 从底层数组创建slice
weekend := week[5:7] // [i:j] 取索引i-j-1的元素作为底层数组,[:j] 取第一个元素到j-1的元素, [1:]取第一个元素到最后一个元素, [:] 取所有元素
week := []int{1,2,3}
week := make([]int, 3,3) // 创建长度为3, 容量为3的slice
使用slice
// 追加元素
week.append(1) // 向slice week追加一个元素1
// 复制slice
var days = []int
copy(days, week) // 将week复制给days
三、散列表(map)
散列表:map[key]value。key为键的类型,value为值的类型。map的零值是nil。
创建map:
// 使用make
ages := make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34
// 使用字面量
ages := map[string]int{"alice": 31, "charlie": 34}
遍历map:
for name, age := ages {
fmt.Printf("%s/t%d/n", name, age)
}
四、结构体
结构体是将零个或者任意类型的命名变量组合在一起的聚合数据类型,每个变量叫做结构体的成员。结构体成员的顺序不同则结构体也不同(两个结构体),如果结构体的成员首字母是大写的,则这个成员变量是可导出的,否则不可导出。结构体中不可定义一个结构体自身类型的变量,但可定义一个自身类型的指针。结构体的零值有结构体成员的零值组成。
定义结构体:
type Employee struct {
ID int
Name string
Address string
Dob string
Position string
Salary string
ManagerId string
}
// 定义一个空结构体
struct {}
// 空结构体可以用作map的值
week := make(map[string]struct{})
定义结构体变量:
var dilbert Employee
给结构体变量常用赋值和访问结构体变量成员:
// 赋值
dilbert.Name = "alice"
// 取值
fmt.Printf("%s\n", dilbert.Name)
// 使用指针访问
position := &dilbert.Position
fmt.Printf("%s\n", *position)
var employee *Employee = &dilbert
// 下面两条语句是等价的
employee.Position = "proactive team player"
(*employee).Position = "proactive team player"
// 使用结构体字面量初始化
type Point struct {X,Y int}
e := Employee{ID: 1, Name: "alice"} // 未赋值的成员将初始化为零值。
p = Point{1,2}
// 初始化结构体,并获取指针
pp := &Point{1,2}
// 等价于
pp := new(Point)
*pp = Point{1,2}
结构体嵌套
type Point struct {X, Y int}
type Circle struct {
Center Point
Radius int
}
type Wheel struct {
Circle Circle
Spokes int
}
// 访问嵌套成员
vat w Wheel
w.Circle.Center.X = 8
w.Circle.Center.Y = 8
w.Circle.Radius = 5
w.Spokes = 20
// 初始化(下面两种方式是等价的)
w = Wheel{Circle{Point{8,8},5}, 20}
w = Wheel{
Circle : Circle {
Point: Point{X:8, Y: 8},
Radius: 5,
}
Spokes: 20,
}
匿名成员
type Circle struct {
Point // 匿名成员,拥有一个隐式的名字Point(类型名),不能定义两个相同类型的匿名成员
Radius int
}
type Wheel struct {
Circle
Spokes int
}
// 访问嵌套成员
vat w Wheel
w.X = 8
w.Y = 8
w.Radius = 5
w.Spokes = 20
结构体方法:
方法的声明和函数类似,只是在函数名字前面多了一个参数,这个参数八这个方法绑定到这个参数对于的类型上。Go可以将方法绑定到任何类型上(指针类型和接口类型除外)。
// 结构体Point的方法, p 参数称为方法的接收者(类似java中的this)
func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.x, q.Y-p.Y)
}
// 方法调用
p := Point{1,2}
q := Point{4,6}
p.Distance(q)
// 使用类型Point的指针作为方法接收者
func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}
// 方法调用
p := &Point{1,2}
p.ScaleBy(2)
// 上面的调用可以简写成
p := Point{1,2}
p.ScaleBy(2) // 编译器会为p执行 &p
五、JSON
Go通过标准库encoding/json对JSON提供了支持。
GO对象转换JSON:
var employee []Employee
data: err := json.Marshal(employee)
data: err := json.MarshalIndent(employee, "", " ")
六、接口
接口类型是对其它类型行为的概括与抽象。对于一个具体的类型,无需声明它实现了哪些接口,只要提供接口所必需的方法即可。。
定义接口:
type Reader interface {
Read(p []byte) (n int, err error)
}
嵌入式接口:
type Reader interface {
Read(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
实现接口:
如果一个类型要实现接口,就必须实现接口类型中定义的所有方法
// 结构体File实现了接口Reader
type File struct {/**....**/}
func (f *File) Read(p []byte) {
/**
.....
**/
}
空接口:
interface {}
var any interface{} // 可以把任何值赋给空接口类型。
接口值:
接口值分为一个接口的具体类型和该类型的一个值(动态类型和动态值)