定义
type Person struct {
Name string
Age uint8
}
func main() {
方式一
var p1 Person
p1.Name="jack"
p1.Age=19
fmt.Println(p1)//{jack 19}
方式二
//var p2 Person =Person{"tom",20}与下面等价
var p2 Person =Person{}
p2.Name="tom"
p2.Age=20
fmt.Println(p2)//{tom 20}
方式三
var p3 *Person = new(Person) //注意通过new方式创建的实例,类型是一个指针
(*p3).Name="mary"//标准方式,为什么不能*p3.Name,因为.的优先级比*高
p3.Age=21//简化方式
fmt.Println(*p3)//{mary 21}
方式四
//var p4 *Person = &Person{"Allen",22}与下面等价
var p4 *Person = &Person{}
(*p4).Name="Allen"//标准方式
p4.Age=22//简化方式
fmt.Println(*p4)//{Allen 22}
方式五
var p4 *Person = &Person{Name:"Allen"} //指定名称初始化,不需要将全部参数赋值
}
细节
实例里的属性的地址是连续分布的
type Human struct {
Name int64
Age int64
Sex int64
}
func main() {
h1 :=Human{}
h1.Name=11
h1.Age=11
h1.Sex=11
fmt.Printf("h1%p\n",&h1)
fmt.Printf("h1.Name%p\th1.Age:%p\th1.Sex:%p",&h1.Name,&h1.Age,&h1.Sex)
//h1.Name0xc000010380 h1.Age:0xc000010388 h1.Sex:0xc000010390
//h1实例里的属性的地址是连续分布的
//并且同数组,切片,map等一样,本身的地址与第一个元素的地址相同
}
_
tag标签
type Human1 struct {
Name string
Age int64
Sex string
}
type Human2 struct {
Name string `json:"name"`
Age int64 `json:"age"`
Sex string `json:"sex"`
}
func main() {
h1 :=Human1{"tom",10,"男"}
h2 :=Human2{"mary",20,"女"}
h1str,_ := json.Marshal(h1)
h2str,_ := json.Marshal(h2)
fmt.Println(string(h1str))//{"Name":"tom","Age":10,"Sex":"男"}
fmt.Println(string(h2str))//{"name":"mary","age":20,"sex":"女"}
}
结构体支持匿名字段与基本类型的匿名字段
type A struct {
int
n int
}
func main() {
a :=A{1,2}
fmt.Println(a.int,a.n)
}
面对对象的思想
工厂模式
utlis包
type student struct {
Name string
age int8
}
//由于student的首字母是小写的,因此在别的pck中是不能使用的
func GetStudent(name string,age int8) *student{
return &student{
Name:name,
age:age,
}
}
//由于student中age字段是首字母是小写的,因此该字段在别的包是访问不到的
func (s *student) GetAge() int8{
return s.age
}
main包
func main() {
s :=utlis.GetStudent("张三",18)
fmt.Println("姓名=",s.Name,"年龄=",s.GetAge())
}
继承
type Animal struct {
Name string
Age int8
}
func (A *Animal) Eat(){
fmt.Println(A.Name,"要吃东西")
}
func (A *Animal) Drink(){
fmt.Println("喝水")
}
type Dog struct {
Animal//实现继承
Name string //重写属性
}
func (D *Dog) Eat(){ //重写方法
fmt.Println(D.Name,"吃骨头")
}
func main() {
//var d Dog=Dog{Animal{"旺财一号",3},"旺财二号"}//可以这样定义
var d Dog
//如果d.Animal.Name="旺财",Animal中Eat()方法中A.Name才拿到值
//但是由于Dog重写了Name属性,设置d.Animal.Name="旺财",Dog中的Eat()方法中D.Name拿不到值
d.Name="旺财"
d.Age = 8 //由于dog是继承于animal的,d.Animal.Age = 8相关等价
d.Eat()//狗吃骨头
d.Animal.Eat()//''要吃东西,
}
注意事项
- 父类的私有属性与方法可以被子类继承
有名结构体在指定属性与方法时要带上名字
type Animal struct {
Name string
Age int8
}
type Dog struct {
A Animal//有名结构体
}
func main() {
var d Dog
//d.Name = "旺财",语法不通过
d.A.Name = "旺财"
}
结构体嵌套多个匿名结构体,且结构体有相同的属性与方法(同时结构体本身没有定义相同的属性与方法),那么在访问时,需要指定匿名结构体的名字
type A struct {
Name string
Age int8
}
type B struct {
Name string
Age int8
Sex string
}
type C struct {
A
B
}
func main() {
var c C
//c.Name="旺财" //语法不通过,A与B中都有Name属性
c.A.Name="旺财"
c.Sex="男" //只有B中有Sex属性,所以可以这样使用
}
组合嵌套的其他定义方式
type A struct {
Name string
Age int8
}
type B struct {
Sex string
}
type C struct {
A
B
}
type D struct {
*A
*B
}
func main() {
方式一:
var c C=C{A{"旺财一号",3},B{"男"}}
方式二:
var c2 C=C{
A{
Name:"旺财二号",
Age:3,
},
B{
Sex:"男",
},
}
指针型方式一:
d :=D{&A{"旺财三号",3},&B{"男"}}
指针型方式二:类似普通型方式二
fmt.Println(*d.A,*d.B)//注意这里不能用(*d).A,d不是指针,d.A才是指针
}
结构体内字段分布具有连续性
1.结构体内无引用类型
type Person struct {
Name string
Age int8
Addr string
}
func main() {
p := &Person{
Name:"aaa",
Age:20,
Addr:"***",
}
fmt.Printf("p变量地址:%p\n", &p) // 0xc000098018
fmt.Printf("Person地址:%p\n", p) // 0xc000074330
fmt.Printf("Name地址:%p\n", &p.Name) // 0xc000074330
fmt.Printf("Age地址:%p\n", &p.Age) // 0xc000074340
fmt.Printf("Addr地址:%p\n", &p.Addr) // 0xc000074348
}
内存分布图
2.结构体内有引用类型
还是具有连续性的特征
type Person struct {
Cars []string
Name string
Age int8
Addr string
}
func main() {
p := &Person{
Cars:[]string{"audi","buick"},
Name:"aaa",
Age:20,
Addr:"***",
}
fmt.Printf("p变量地址:%p\n", &p) // 0xc000098018
fmt.Printf("Person地址:%p\n", p) // 0xc00001a0c0
fmt.Printf("Cars地址:%p\n", &p.Cars) // 0xc00001a0c0
fmt.Printf("Name地址:%p\n", &p.Name) // 0xc00001a0d8
fmt.Printf("Age地址:%p\n", &p.Age) // 0xc00001a0e8
fmt.Printf("Addr地址:%p\n", &p.Addr) // 0xc00001a0f0
}
3.%v与%p的理解
type InfoS struct {
Addr string
}
type Person1 struct {
Info *InfoS
}
func main() {
p := &Person1{new(InfoS)}
fmt.Printf("%p\n", &p) // 0xc000006028
fmt.Printf("%p\n", p) // 0xc000006030
fmt.Printf("%p\n", p.Info) // 0xc00003a1f0
fmt.Printf("%p\n", &p.Info) // 0xc000006030
fmt.Printf("%v\n", p) // &{0xc00003a1f0}
// p存的是指针,用%v时,如果是指针类型,会默认对指针做一次取值操作,注意是一次
}
其他
类型为func
type Myfunc func(i, n int64) bool
func (m Myfunc) run1(i, n int64) bool {
return m(1, 2)
}
func (m Myfunc) run2(i, n int64) bool {
return i > n
}
func main() {
f := Myfunc(func(i, n int64) bool {
return i < n
})
fmt.Println(f.run1(1, 2), f.run2(1, 2)) //true false
}