- Go 数组
- Go 切片
- Go 变量和内存地址
- Go Map 类型
- Go 面向对象编程
- Go 方法的定义
GO 数组
数组是同一类型的元素集合。Go中的数组下标从0开始,因此长度为n的数组下标范围是[0, n-1]。
整数数组中元素默认初始化为0,字符串数组中的元素默认初始化为""。
var a [3]int
a[0] = 10
a[1] = 20
var a [3]int = [3]int{10, 20, 30}
//定义时数组初始化
//数组初始化
var a [3]int = [3]int{10, 20, 30}
//定义时数组初始化
a := [3]int{10, 20, 30}
//定义时数组初始化
a := [...]int{10, 20, 30}
//定义时数组初始化
a := [3]int{10}
//定义时数组初始化
a := [3]int{2:10}
//定义时数组初始化
- 数组⻓度是类型的⼀部分
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
var b [5]int
b=a
//a、b是不同类型的数组,不能赋值
- len 内置函数
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
fmt.Printf(“len:%d\n”, len(a))
- 数组的遍历
a. 下标进行遍历
b. range 函数进行遍历
range函数是个神奇而有趣的内置函数,你可以使用它来遍历数组,切片和字典。
当用于遍历数组和切片的时候,range函数返回索引和元素。
当用于遍历字典的时候,range函数返回字典的键和值。
package main
import "fmt"
func main() {
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
// 使用下标遍历
for i := 0; i // fmt.Printf(a[i] + " ")
}
for index, val := range a {
// fmt.Printf(a[i] + " ")
}
// 这里我们使用range来计算一个切片的所有元素和
// 这种方法对数组也适用
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
// range 用来遍历数组和切片的时候返回索引和元素值
// 如果我们不要关心索引可以使用一个下划线(_)来忽略这个返回值
// 当然我们有的时候也需要这个索引
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
// 使用range来遍历字典的时候,返回键值对。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
// range函数用来遍历字符串时,返回Unicode代码点。
// 第一个返回值是每个字符的起始字节的索引,第二个是字符代码点,
// 因为Go的字符串是由字节组成的,多个字节组成一个rune类型字符。
for i, c := range "go" {
fmt.Println(i, c)
}
}
sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111
- Go数组排序
Go 分别提供了sort.Float64s() sort.Strings() sort.Ints() 对不同类型的数组进行排序,默认是升序。
降序需要使用sort.Reverse。
package mainimport ("fmt""sort"
)
func main() {
arrayInt := []int{3, 1, 2, 5, 4}
arrayFloat := []float64{3.2, 1.8, 1.9, 2.2, 4.3}
arrayString := []string{"abc", "ab", "bc"}
// 升序
sort.Ints(arrayInt)
sort.Float64s(arrayFloat)
sort.Strings(arrayString)
fmt.Println("sort int:", arrayInt)
fmt.Println("sort float:", arrayFloat)
fmt.Println("sort ", arrayString)
// 降序
sort.Sort(sort.Reverse(sort.IntSlice(arrayInt)))
sort.Sort(sort.Reverse(sort.Float64Slice(arrayFloat)))
sort.Sort(sort.Reverse(sort.StringSlice(arrayString)))
fmt.Println("After reversed: ")
fmt.Println("sort int:", arrayInt)
fmt.Println("sort float:", arrayFloat)
fmt.Println("sort ", arrayString)
}
- 数组的拷贝和传参
a. 数组是值类型
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
b := a
//b拷⻉了数组a中所有元素
b[0] = 1000
a: [10,20,30]
b: [1000,20,30]
b. 数组是值类型,函数传参也会拷⻉
package mainimport ("fmt")
func main() {
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
modify(a)
fmt.Println(a) // [10,20,30]
}
func modify(b [3]int) {
b[0] = 1000
fmt.Println(b) // [1000,20,30]
return
}
GO 切片
GO的切片是基于数组类型的一层封装。Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
var a []int
//定义⼀个int类型的空切⽚
- 切⽚初始化, a[start:end]创建⼀个包括从start到end-1的切⽚。
package mainimport ("fmt"
)
func main() {
// 初始化方法1
a:= [5]int{76, 77, 78, 79, 80}
var b []int = a[1: 4] //基于数组a
// 创建⼀个切⽚,包括元素a[1] a[2] a[3]
fmt.Println(b)
// 初始化方法2
c:=[]int{6, 7, 8} //创建一个数组并返回⼀个切⽚
fmt.Println(c)
}
- 数组切片的基本操作
a. arr[start:end]:包括start到end-1(包括end-1)之间的所有元素
b. arr[start:]:包括start到arr最后⼀个元素(包括最后一个元素)之间的所有元素
c. arr[:end]:包括0到end-1(包括end-1)之间的所有元素
d. arr[:]:包括整个数组的所有元素
- 切⽚修改
package mainimport ("fmt"
)
func main() {
//创建⼀个数组,其中[...]是编译器确定数组的长度,darr的长度是9
darr:=[...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
//基于darr创建⼀个切⽚dslice,包括darr[2],darr[3],darr[4]三个元素
dslice:=darr[2:5]
fmt.Println("array before",darr)
for i:=range dslice {
//对于dslice中每个元素进行+1,其实修改是darr[2],darr[3],darr[4]
dslice[i]++
}
fmt.Println("array after",darr)
}
// array before [57 89 90 82 100 78 67 69 59]
// array after [57 89 91 83 101 78 67 69 59]
切片是数组的引用,当两个切片源于一个数组,改变其中一个数组,另一个数组也响应的进行的修改。
package mainimport ("fmt"
)
func main() {
numa:=[3]int{78, 79 ,80}
//创建⼀个切⽚,包含整个数组的所有元素
nums1 := numa[:]
nums2 := numa[:]
fmt.Println("array before change 1",numa)
nums1[0]= 100
fmt.Println("array after modification to slice nums1", numa)
nums2[1]=101
fmt.Println("array after modification to slice nums2", numa)
}
// array before change 1 [78 79 80]
// array after modification to slice nums1 [100 79 80]
// array after modification to slice nums2 [100 101 80]
- 使⽤make创建切片
make为内建类型slice、map和channel分配内存。
package mainimport ("fmt"
)
func main() {
//[]中没有⻓度 第一个5 是切片的长度,第二个 5是切片的容量
i:=make([]int, 5, 5)
fmt.Println(i)
}
// [0 0 0 0 0]
- 切片的⻓度和容量
package mainimport ("fmt"
)
func main() {
var a []int
a =make([]int, 5, 10)
a[0] = 10
fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a)) // a=[10 0 0 0 0] addr:0xc0000a0000 len:5 cap:10
a= append(a,11)
fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a)) //a=[10 0 0 0 0 11] addr:0xc00009e000 len:6 cap:10
for i:=0; i 8;i++ {
a= append(a, i)
fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))
// a=[10 0 0 0 0 11 0] addr:0xc00009e000 len:7 cap:10
// a=[10 0 0 0 0 11 0 1] addr:0xc00009e000 len:8 cap:10
// a=[10 0 0 0 0 11 0 1 2] addr:0xc00009e000 len:9 cap:10
// a=[10 0 0 0 0 11 0 1 2 3] addr:0xc00009e000 len:10 cap:10
// a=[10 0 0 0 0 11 0 1 2 3 4] addr:0xc0000a4000 len:11 cap:20
// a=[10 0 0 0 0 11 0 1 2 3 4 5] addr:0xc0000a4000 len:12 cap:20
// a=[10 0 0 0 0 11 0 1 2 3 4 5 6] addr:0xc0000a4000 len:13 cap:20
// a=[10 0 0 0 0 11 0 1 2 3 4 5 6 7] addr:0xc0000a4000 len:14 cap:20
}
// 观察切片的扩容操作 扩容的策略是翻倍扩容
a = append(a,1000)
fmt.Printf("a=%v addr:%p len:%d cap:%d\n", a,a,len(a),cap(a))
// a=[10 0 0 0 0 11 0 1 2 3 4 5 6 7 1000] addr:0xc0000200a0 len:15 cap:20
}
例子2:
package mainimport ("fmt"
)
func main() {
fruitarray :=[...]string{
"apple", "orange", "grape",
"mango", "water melon",
"pine apple", "chikoo"}
fruitslice:=fruitarray[1:3]//长度是2,容量is 6
fmt.Printf("length of slice %d capacity %d",len(fruitslice), cap(fruitslice))
}
// length of slice 2 capacity 6
- 切片再切片
package mainimport ("fmt"
)
func main() {
fruitarray:=[...]string{
"apple", "orange", "grape", "mango",
"water melon", "pine apple", "chikoo"}
fruitslice:=fruitarray[1:3]
//长度是2, 容量是6
fmt.Printf("length of slice %d capacity %d\n",len(fruitslice), cap(fruitslice))
//再重新进行切⽚,不能⼤于数组fruitarray的⻓度,否则越界
fruitslice = fruitslice[:cap(fruitslice)]
fmt.Println("After re-slicing length is",len(fruitslice), "and capacity is",cap(fruitslice))
}
// length of slice 2 capacity 6
// After re-slicing length is 6 and capacity is 6
- append 操作
package mainimport ("fmt"
)
func main() {
cars:=[]string{"Ferrari", "Honda", "Ford"}
//⻓度和容量都等于3
fmt.Println("cars:", cars, "has old length",len(cars), "and capacity", cap(cars))
cars=append(cars, "Toyota")
//容量等于6
fmt.Println("cars:", cars, "has new length",len(cars), "and capacity", cap(cars))
}
// cars: [Ferrari Honda Ford] has old length 3 and capacity 3
// cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6
a. append⼀个切⽚
package mainimport ("fmt"
)
func main() {
veggies:=[]string{"potatoes","tomatoes","brinjal"}
fruits :=[]string{"oranges","apples"}
//fruits后⾯的3个点表示展开fruits切⽚成⼀个元素
food:= append( veggies, fruits...)
fmt.Println("food:",food)
}
// food: [potatoes tomatoes brinjal oranges apples]
- 空切片
package mainimport ("fmt"
)
func main() {
//定义names是⼀个空切⽚,⻓度和容量都等于0
//不能对空切⽚进行访问,否则panic
var names []string
if names == nil {
fmt.Println("slice is nil going to append")
names = append(names, "John", "Sebastian", "Vinay")
fmt.Println("names contents:",names)
}
}
- 切片传参
package mainimport ("fmt"
)//在函数内部修改numbers切⽚的值
func subtactOne(numbers []int) {
for i:= range numbers {
numbers[i]-=2
}
}
func main() {
nos:=[]int{8, 7, 6}
fmt.Println("slice before function call", nos)
subtactOne(nos)
//nos修改⽣效了,说明切片是引⽤类型
fmt.Println("slice after function call", nos)
}
// slice before function call [8 7 6]
// slice after function call [6 5 4]
- 切片深拷贝
package mainimport ("fmt"
)
func main() {
// 当元素数量超过容量
// 切片会在底层申请新的数组
slice := make([]int, 5, 5)
slice1 := slice
slice = append(slice, 1)
slice[0] = 1
fmt.Println(slice)//[1 0 0 0 0 1]
fmt.Println(slice1)//[0 0 0 0 0]
// copy 函数提供深拷贝功能
// 但需要在拷贝前申请空间
slice2 := make([]int, 4, 4)
slice3 := make([]int, 5, 5)
fmt.Println(copy(slice2, slice))//4
fmt.Println(copy(slice3, slice))//5
fmt.Println(slice2)// [1 0 0 0]
fmt.Println(slice3)// [1 0 0 0 0]
slice2[1] = 2
slice3[1] = 3
fmt.Println(slice)//[1 0 0 0 0 1]
fmt.Println(slice2)//[1 2 0 0]
fmt.Println(slice3)//[1 3 0 0 0]
}
- 切片遍历
var a [3]int
a[0] = 10
a[1] = 20
a[2] = 30
B := a[:]
for index, val := range b {
}
//和数组遍历是⼀样的
- new⽤于各种类型的内存分配,new返回是⼀个指针
Go 变量和内存地址
每个变量都有内存地址,可以说通过变量来操作对应⼤大⼩小的内存 。注意:通过&符号可以获取变量的地址。
普通变量存储的是对应类型的值,这些类型就叫值类型 例: var a int32。
指针类型的变量存储的是一个地址,所以⼜叫指针类型或引用类型, 在定义时,前方加*就变为引用类型,var a *int32, a中存储的是一个地址,我们称为引用类型或者指针类型。
package mainimport ("fmt"
)
func main() {
var a int32
a = 100
fmt.Printf("%d\n", a)
fmt.Printf("%p\n", &a)
b:=255
var c *int = &b
fmt.Printf("Type of c is %T\n", c)
fmt.Println("address of b is", c)
}
// 100
// 0xc00001608c
// Type of a is *int
// address of b is 0xc00009a008
- 指针类型变量的默认值为nil,也就是空地址
package mainimport ("fmt"
)
func main() {
a := 25
var b *int
if b == nil {
fmt.Println("b is", b)
b = &a
fmt.Println("b after initialization is", b)
}
}
// b is
// b after initialization is 0xc0000a2008
- 如果操作指针变量指向的地址里面的值呢?
注意:通过* 符号可以获取指针变量指向的变量。
package mainimport ("fmt"
)
func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is",*a)
}
// address of b is 0xc00009a008
// value of b is 255
- 通过指针修改变量的值
package mainimport ("fmt"
)
func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a)
*a++
fmt.Println("new value of b is",b)
}
// address of b is 0xc00009a008
// value of b is 255
// new value of b is 256
- 指针变量传参
package mainimport ("fmt"
)
func change (val *int){
*val = 55
}
func main() {
a := 255
fmt.Println("value of a before function call is",a)
b := &a
change(b)
fmt.Println("value of a after function call is", a)
}
// value of a before function call is 255
// value of a after function call is 55
// 例子2
func change (arr *[3]int){
(*arr)[0] = 90
}
func main() {
a:=[3]int{89, 90, 91}
change(&a)
fmt.Println(a)
}
// [90 90 91]
对比 切片传参注意:切片是引用类型!!
func change (arr []int){
arr[0] = 90
}
func main() {
a:=[3]int{89, 90, 91}
change(a[:])
fmt.Println(a)
}
// [90 90 91]
// make⽤来分配引⽤类型的内存,⽐如 map、slice以及channel ,new⽤来分配除引用类型的所有其他类型的内存,⽐如 int、数组等
- 值拷⻉和引⽤拷⻉
package mainimport ("fmt"
)
func main() {
// 值拷贝
var a int = 100
b := a
// 引用拷贝
var a int = 100
var b *int = &a
var c *int = b
*c = 200
}
Go Map 类型
map类型是⼀个key-value的数据结构。注意:map必须初始化才能使⽤,否则panic。
map类型的变量默认初始化为nil,需要使用make分配map内存。
//var a map[key的类型]value类型
var a map[string]int
var b map[int]string
var c map[float32]string
package mainimport ("fmt"
)
func main() {
var a map[string]int
if a == nil {
fmt.Println("map is nil. Going to make one.")
a = make(map[string]int)
}
}
- map插入操作
package mainimport ("fmt"
)
func main() {
a := make(map[string]int)
a["steve"] = 12000
a["jamie"] = 15000
a["mike"] = 9000
fmt.Println("a map contents:", a)
}
// a map contents: map[jamie:15000 mike:9000 steve:12000]
- map 声明方式二, 通过key访问map中的元素
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
fmt.Println("a map contents:", a)
}
- 如何判断map指定的key是否存在? value, ok := map[key]
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
b := "joe"
value, ok := a[b]
if ok == true {
fmt.Println("Salary of", b, "is", value)
} else {
fmt.Println(b,"not found")
}
fmt.Println("a map contents:", a)
}
// joe not found
// a map contents: map[jamie:15000 mike:9000 steve:12000]
- map遍历操作
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
for key, value:= range a {
fmt.Printf("personSalary[%s] = %d\n", key, value)
}
}
// personSalary[steve] = 12000
// personSalary[jamie] = 15000
// personSalary[mike] = 9000
- map删除元素
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
delete(a, "steve")
fmt.Println("map after deletion", a)
}
// map after deletion map[jamie:15000 mike:9000]
- map的⻓度 len(a)
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
fmt.Println("length is", len(a))
}
// length is 3
- map是引⽤类型
package mainimport ("fmt"
)
func main() {
a := map[string]int {
"steve": 12000,
"jamie": 15000,
}
a["mike"] = 9000
b := a
b["mike"] = 18000
fmt.Println("a map changed", a)
}
// a map changed map[jamie:15000 mike:18000 steve:12000]
- 默认情况下,map并不是按照key有序进⾏遍历的 ,map按照key进行排序,遍历 。
package mainimport ("fmt""sort"
)
func main() {
var a map[string]int = make(map[string]int, 10)
for i := 0; i 10; i++ {
key := fmt.Sprintf("key%d", i)
a[key] = i
}
var keys []string
for key, _ := range a {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
fmt.Printf("key:%s=%d\n", key, a[key])
}
}
// key:key0=0
// key:key1=1
// key:key2=2
// key:key3=3
// key:key4=4
// key:key5=5
// key:key6=6
// key:key7=7
// key:key8=8
// key:key9=9
- map类型的切⽚
package mainimport ("fmt"
)
func main() {
var mapSlice []map[string]int
mapSlice = make([]map[string]int, 5)
fmt.Println("before map init")
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
mapSlice[0] = make(map[string]int, 10)
mapSlice[0]["a"] = 1000
mapSlice[0]["b"] = 2000
mapSlice[0]["c"] = 3000
mapSlice[0]["d"] = 4000
mapSlice[0]["e"] = 5000
fmt.Println("after map init")
for index, value := range mapSlice {
fmt.Printf("index:%d value:%v\n", index, value)
}
}
// before map init
// index:0 value:map[]
// index:1 value:map[]
// index:2 value:map[]
// index:3 value:map[]
// index:4 value:map[]
// after map init
// index:0 value:map[a:1000 b:2000 c:3000 d:4000 e:5000]
// index:1 value:map[]
// index:2 value:map[]
// index:3 value:map[]
// index:4 value:map[]
Go 面向对象编程
- struct声明和定义
Go中⾯向对象是通过struct来实现的, struct是用户⾃定义的类型 , 注意:type是⽤来定义⼀种类型
type User struct {
Username string
Sex string
Age int
AvatarUrl string
}
初始化 方法分为两种:
方法一:
注意:使⽤变量名+ ‘.’ + 字段名访问结构体中的字段
var user User
user.Age = 18
user.Username = “user01”
user.Sex = “男”
user.AvatarUrl = “http://my.com/xxx.jpg"
方法二:
var user User = User {
“Username” : “user01”,
“Age”: 18,
“Sex”: “男”,
“AvatarUrl”: “http://my.com/xxx.jpg”,
}
更简单的写法:
user := User {
“Username” : “user01”,
“Age”: 18,
“Sex”: “男”,
“AvatarUrl”: “http://my.com/xxx.jpg”,
}
- struct初始化的默认值是什么?
var user User
fmt.Printf(“%#v\n”, user)
- 结构体类型的指针
注意:&User{}和new(User) 本质上是⼀样的,都是返回一个 结构体的地址
package mainimport ("fmt"
)
func main() {
var user *User = &User{}
fmt.Printf(“%p %#v\n”, user)
// 直接初始化:
var user *User = &User {
Username : “user01”,
Age: 18,
Sex: “男”,
AvatarUrl: “http://my.com/xxx.jpg”,
}
// 或者使用new
var user User = new(User)
user.Age = 18
user.Username = “user01”
user.Sex = “男”
user.AvatarUrl = “http://my.com/xxx.jpg"
}
- 结构体的内存布局: 占⽤⼀段连续的内存空间
结构体没有构造函数, 必要时需要⾃⼰实现
匿名字段: 即没有名字的字段 注意:匿名字段默认采用类型名作为 字段名
type User struct {
Username string
Sex string
Age int
AvatarUrl string
}
type User struct {
Username string
Sex string
Age int
AvatarUrl string
int
string
}
- 结构体嵌套
type Address struct {
City string
Province string
}
type User struct {
Username string
Sex string
Age int
AvatarUrl string
address *Address
}
func main () {
user := &User {
Username: 'user01',
Sex: 'man',
address: &Address {
Province: 'beijing',
City: 'beijing',
},
}
}
- 匿名结构体
第二种方式 先在结构体里面找Provice以及City,如果结构体里面没有,则在匿名结构体里面找,
type Address struct {
City string
Province string
}
type User struct {
Username string
Sex string
Age int
AvatarUrl string
*Address
}
func main () {
var user User
user.Username = 'user01'
user.Sex = 'man'
// 第一种方式
user.Address = &Address{
Provice: 'bj',
City: 'bj'
}
// 第二种方式
user.Province = 'bj01'
user.City = 'bj01'
}
- 匿名结构体的冲突解决 使用结构体的字段,如果结构体字段有值,则使用结构体,如果没有则使用匿名结构体的字段 如果两个匿名结构体都有相同的字段,当访问这个相同字段时候,要指定访问那个匿名结构体的字段
package mainimport ("fmt"
)
type Address struct {
City string
Province string
CreateTime string
}
type Email struct {
Account string
CreateTime string
}
type User struct {
Username string
Sex string
Age int
AvatarUrl string
*Address
*Email
CreateTime string
}
func main (){
var user User
user.Username = "user01"
user.Sex = "man"
user.City = "bj"
user.Address = new(Address)
user.Email = new(Email)
user.Address.City ="bj01"
user.Address.CreateTime ="001"
user.Email.CreateTime = "002"
fmt.Println( user.Email.CreateTime, user.Address.CreateTime)
}
- 字段可⻅性,⼤写表示可公开访问,⼩写表示私有
type User struct {
Username string
Sex string
Age int
avatarUrl string // 私有
CreateTime string
}
- tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来 字段类型后⾯,以反引号括起来的 key-value结构的字符串,多个tag 以逗号隔开。
type User struct {
Username string `json:”username”,db:”user_name”`
Sex string `json:”sex”`
Age int `json:”age”`
avatarUrl string
CreateTime string
}
Go 方法的定义
和其他语⾔不⼀样,Go的⽅法采⽤另外⼀种⽅式实现
Go的⽅法是在函数前⾯加上一个接受者,这样编译器就知道这个⽅法属于哪个类型了
- 可以为当前包内定义的任何类型增加方法
- 函数和方法的区别: 函数不属于任何类型,⽅法属于特定的类型
- 指针类型作为接受者
- 指针类型和值类型作为接受者的区别
值类型:
type People struct {
Name string
Country string
}
func (p People) Print() {
fmt.Println("name=%s country=%s\n",p.Name, p.Country)
}
func (p People) Set(name string, country string) {
p.Name = name
p.Country = country
}
func main() {
var p1 People = People {
Name: "people01",
Country: "china",
}
p1.Print() // people01 china
p1.Set("people02","english")
p1.Print() // 不变 p是实例的拷贝 people01 china
}
指针类型:
type People struct {
Name string
Country string
}
func (p People) Print() {
fmt.Println("name=%s country=%s\n",p.Name, p.Country)
}
// 值类型
func (p People) Set(name string, country string) {
p.Name = name
p.Country = country
}
// 引用类型
func (p *People) SetV2(name string, country string) {
p.Name = name
p.Country = country
}
func main() {
var p1 People = People {
Name: "people01",
Country: "china",
}
p1.Print() // people01 china
p1.Set("people02","english")
p1.Print() // 不变 p是实例的拷贝 people01 china
(&p1).SetV2("people02","english")或 语法糖: p1.SetV2("people02","english")
p1.Print() // 变了 people02 english
}
- 什么时候用值类型/指针类型作为接受者?
a. 需要修改接受者中的值的时候 b. 接受者是⼤对象的时候,副本拷贝代价⽐较大 c. ⼀般来说,通常使⽤指针类型作为接受者
- 匿名结构体与继承
通过组合 和 匿名字段实现的继承,方法的冲突解决和匿名字段的冲突解决一致,都是通过指定对应的实例的方法解决
type Anaimal struct {
Name string
Sex string
}
func (a *Anaimal) Talk() {
fmt.Println(a.Name)
}
type Dog struct {
Feet string
*Anaimal
}
func (d *Dog) Eat () {
fmt.Println("dog is eat")
}
func main () {
var d *Dog = &Dog{
Feet: "Four Feet",
Anaimal: &Anaimal {
Name: "dog",
Sex: "xiong",
},
}
d.Name = "dog"
d.Sex = "xiong"
d.Eat()
d.Talk()
}
- 多重继承与冲突解决
type Mother struct {
Name string
}
type Father struct {
Name string
}
type People struct {
Sex string
Age int
*Mother
*Father
}
- 结构体与json序列列化
package mainimport ("encoding/json""fmt"
)
type Student struct {
Id string
Name string
Sex string
}
type Class struct {
Name string
Count int
Students []*Student
}
var rawJson = `
{"Name":"101","Count":0,"Students":[{"Id":"0","Name":"stu0","Sex":"man"},{"Id":"1","Name":"stu1","Sex":"man"},{"Id":"2","Name":"stu2","Sex":"man"},{"Id":"3","Name":"stu3","Sex":"man"},{"Id":"4","Name":"stu4","Sex":"man"},{"Id":"5","Name":"stu5","Sex":"man"},{"Id":"6","Name":"stu6","Sex":"man"},{"Id":"7","Name":"stu7","Sex":"man"},{"Id":"8","Name":"stu8","Sex":"man"},{"Id":"9","Name":"stu9","Sex":"man"}]}
`
func main() {
c := &Class{
Name: "101",
Count: 0,
}
for i := 0; i 10; i++ {
stu := &Student{
Name: fmt.Sprintf("stu%d", i),
Sex: "man",
Id: fmt.Sprintf("%d", i),
}
c.Students = append(c.Students, stu)
}
data, err := json.Marshal(c)
if err != nil {
fmt.Println("json marshal failed")
return
}
fmt.Printf("json:%s\n", string(data))
//json反序列化
fmt.Println("unmarshal result is \n\n")
var c1 *Class = &Class{}
err = json.Unmarshal([]byte(rawJson), c1)
if err != nil {
fmt.Println("unmarhsal failed")
return
}
fmt.Printf("c1:%#v\n", c1)
for _, v := range c1.Students {
fmt.Printf("stu:%#v\n", v)
}
}
推荐阅读
(点击标题可跳转阅读)
RxJS入门
一文掌握Webpack编译流程
一文深度剖析Axios源码
Javascript条件逻辑设计重构
Promise知识点自测你不知道的React Diff你不知道的GIT神操作程序中代码坏味道(上)
程序中代码坏味道(下)
学习Less,看这篇就够了
一文掌握GO语言实战技能(一)
一文掌握Linux实战技能-系统管理篇
一文掌握Linux实战技能-系统操作篇
一文达到Mysql实战水平
一文达到Mysql实战水平-习题答案
从表单抽象到表单中台
vue源码分析(1)- new Vue
实战LeetCode 系列(一) (题目+解析)
一文掌握Javascript函数式编程重点
实战LeetCode - 前端面试必备二叉树算法
一文读懂 React16.0-16.6 新特性(实践 思考)
阿里、网易、滴滴、今日头条、有赞.....等20家面试真题
30分钟学会 snabbdom 源码,实现精简的 Virtual DOM 库
觉得本文对你有帮助?请分享给更多人
关注「React中文社区」加星标,每天进步