在放弃的边缘打滚……
等学完了估计也就忘完了,刚看到之前的笔记发现都陌生得不行,而且之前还有一个有疑问的点说要记录一下,间隔时间长了都忘记是什么了。
虽然markdown很潮流但是也用的非常少,所以还是切换到md模式来记录下,顺便唤起md的记忆
struct 结构体基础概念
struct 可以看成是golang中的类,是golang面向对象的体现
package main
import (
"fmt"
)
//Animal 动物 --结构体注释的方式 结构体名 空格 注释
type Animal struct {
Name string
Age byte
}
//MulitAttribute 多类型属性
type MulitAttribute struct {
I *int
Arr [3]int
Sli []string
Mp map[string]string
}
func main() {
//定义结构体
var cat Animal
cat.Name = "cat"
cat.Age = 2
//需与结构体定义的属性顺序一致
dog := Animal{"dog", 3}
//最后的逗号不可省略
fish := Animal{
Name : "fish",
Age : 4,
}
fmt.Println(cat, dog, fish)
//注意不同类型属性的赋值
matr := MulitAttribute{}
//new函数返回指针
matr.I = new(int)
matr.Sli = make([]string, 2, 4)
matr.Mp = make(map[string]string, 2)
fmt.Println(matr)
i := 9
matr.I = &i
matr.Arr[0] = 1
matr.Arr[1] = 2
matr.Arr[2] = 3
matr.Sli[0] = "sli01"
matr.Sli[1] = "sli02"
matr.Mp["name"] = "demo"
fmt.Println(matr)
fmt.Printf("I = %v, Arr = %v, Sli = %v, Mp = %v \n",
*matr.I, matr.Arr, matr.Sli, matr.Mp)
}
结构体是值拷贝
package main
import "fmt"
type Demo struct {
Str string
Arr [3]int
Sli []string
Mp map[string]string
}
func main() {
first := Demo{}
first.Str = "first"
first.Arr = [3]int{1, 2, 3}
first.Sli = make([]string, 2, 3)
first.Sli[0] = "first01"
first.Sli[1] = "first02"
first.Mp = make(map[string]string, 1)
first.Mp["name"] = "first"
fmt.Printf("first地址: %p \n", &first)
fmt.Println(first)
second := first
fmt.Println(second)
fmt.Printf("first地址: %p, second地址:%p \n", &first, &second)
second.Str = "second"
second.Arr = [3]int{4, 5, 6}
second.Sli[0] = "second01"
second.Sli[1] = "second02"
second.Mp["name"] = "second"
//对了,这个就是我刚刚忘记的那个点
//非引用类型的属性值发生了改变,但引用类型的值被覆盖比如slice 和 map的值被覆盖
fmt.Println("first: ", first)
fmt.Println("second: ", second)
fmt.Printf("first str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&first.Str, &first.Arr, &first.Sli, &first.Mp)
fmt.Printf("second str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&second.Str, &second.Arr, &second.Sli, &second.Mp)
//考虑到在之前学习slice时发现 当slice添加元素扩充容量后 slice原有的地址改变相当于
//新创建的slice与原有的无相互关联,此处将slice和map都增加到超出原有的容量
second.Sli = append(second.Sli, "second03")
second.Mp["addr"] = "second-addr"
second.Mp["attribute"] = "second-attribute"
fmt.Println("------------***--------------")
fmt.Println("first: ", first)
fmt.Println("second: ", second)
fmt.Printf("first str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&first.Str, &first.Arr, &first.Sli, &first.Mp)
fmt.Printf("second str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&second.Str, &second.Arr, &second.Sli, &second.Mp)
//从结果看,超出容量的slice变成了新slice故与原有slice无关了,但map增加元素超出初始容量并没有直接变化
//故重新赋值时也与原有map无关
second.Mp = make(map[string]string, 2)
fmt.Println("------------***--------------")
fmt.Println("first: ", first)
fmt.Println("second: ", second)
fmt.Printf("first str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&first.Str, &first.Arr, &first.Sli, &first.Mp)
fmt.Printf("second str 地址: %p , arr 地址: %p, sli 地址: %p, mp 地址: %p \n",
&second.Str, &second.Arr, &second.Sli, &second.Mp)
//综上,结构体的值拷贝特性值得注意的是结构体内部属性的类型所展现的不同区别,这个坑暂时先留着吧
}
golang结构体的属性信息(名称,类型,个数)完全一致时可以进行强转
package main
import "fmt"
type A struct {
Name string
}
type B struct {
Name string
}
type C struct {
Addr string
}
//结构体进行type重新定义(相当于取别名),golang认为是新的数据类型,但是可以进行强制转换
type AnotherA A
func main() {
a := A{"a"}
fmt.Println(a)
var b B
//不可以直接赋值 a = b,但可以进行强转
b = B(a)
fmt.Println(b)
fmt.Printf("a 地址: %p, b 地址: %p \n", &a, &b)
//结构体属性不一致不可强转 c := C(a)
//AnotherA 为type对A进行重新定义的类型,AnotherA为新类型但可以强转
var anotherA AnotherA
// anotherA = a 不可直接赋值
anotherA = AnotherA(a)
fmt.Printf("anotherA 类型 %T, 地址 %p \n", anotherA, &anotherA)
}
结构体属性的首字母大小写与可见性有关
package main
import (
"encoding/json"
"fmt"
)
type Monster struct {
Name string
attribute string
}
type Demon struct {
Name string
Skill string
}
type Devil struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
m := Monster{"monster", "m"}
d := Demon{"demon", "d"}
//字段首字母小写则意味着访问权限受限,导致json包执行marshal方法时无法访问到该字段
mbytes, _ := json.Marshal(m)
dbytes, _ := json.Marshal(d)
fmt.Println("m json ", string(mbytes))
fmt.Println("d json ", string(dbytes))
//为兼容其他语言习惯(属性首字母大小写问题),golang通过将struct的属性设置tag用于序列化及反序列化
dv := Devil{"devil", 1000}
dvbytes, _ := json.Marshal(dv)
fmt.Println("dv json ", string(dvbytes))
//go 底层对结构体的指针类型做了相应优化
var ms *Monster = &m
//按照定义逻辑写法
fmt.Println((*ms).Name)
//可以简写省去括号
fmt.Println(ms.attribute)
}
还说把方法/继承/接口放一起的,还是算了吧