Go 编程基础 struct 09

结构struct

  • Go中的struct与C中的struct非常相识,并且Go没有Class
  • 使用Type <Name> struct{}定义结构,名称遵循可见性规则
  • 支持指向自身的指针类型成员
  • 支持匿名函数,可用作成员或者定义成员变量
  • 匿名函数也可以用于map的值
  • 可以使用字面值对结构进行初始化
  • 允许直接通过指针来读写结构成员
  • 支持 == 与 != 比较运算符,单不支持 > 或 <
  • 支持匿名字段, 本质上是定义了以某个类型名为名称的字段
  • 嵌入结构可以作为匿名字段看起来像继承, 但不是继承
  • 可以使用匿名字段指针

定义一个简单的struct

type person struct {

}

func main() {
    a := person{}
    fmt.Println(a)
}
{}

因为没有任何属性所以..输出的自然是 {}

带属性的struct

type person struct {
    Name string
    Age  int
}

func main() {
    a := person{}
    a.Name = "ailuoy"
    a.Age = 26
    fmt.Println(a)
}

同样如果你觉得每次赋值都很麻烦.可以使用字面值来赋值

type person struct {
    Name string
    Age  int
}

func main() {
    a := person{
        Name: "ailuoy",
        Age:  26,
    }
    fmt.Println(a)
}
{ailuoy 26}

值传递调用func

type person struct {
    Name string
    Age  int
}

func main() {
    a := person{
        Name: "ailuoy",
        Age:  26,
    }
    A(a)
    fmt.Println(a)
}

func A(p person) {
    p.Name = "hahahah"
    p.Age = 12
    fmt.Println(p)
}
{hahahah 12}
{ailuoy 26}

那么我们这里看到.. 值并没有发生变化,因为我么只是值拷贝

内存拷贝调用func

type person struct {
    Name string
    Age  int
}

func main() {
    a := person{
        Name: "ailuoy",
        Age:  26,
    }
    A(&a)
    fmt.Println(a)
}

func A(p *person) {
    p.Name = "hahahah"
    p.Age = 12
    fmt.Println(p)
}
&{hahahah 12}
{hahahah 12}

只需要传递 &p 内存地址即可, 同时修改的时候取出*p p的值进行修改

多次调用的问题

上面我们只调用了一次A方法.. 所以你成 &p 是没有问题的,, 如果调用的次数过多.. 那岂不是你要写很多次 &p

其实不用的,,我们可以在初始化数据的时候就直接取出内存地址即可

type person struct {
    Name string
    Age  int
}

func main() {
    a := &person{
        Name: "ailuoy",
        Age:  26,
    }
    fmt.Println(a)
    A(a)
    B(a)
    fmt.Println(a)
    a.Name = "mmmmmm"
    fmt.Println(a)
}

func A(p *person) {
    p.Name = "hahahaha"
    p.Age = 12
    fmt.Println(p)
}

func B(p *person) {
    p.Name = "hehehehe"
    p.Age = 13
    fmt.Println(p)
}
&{ailuoy 26}
&{hahahaha 12}
&{hehehehe 13}
&{hehehehe 13}
&{mmmmmm 13}

同时我们申明结构体的时候 & 的话, 那我们重新对结构体的 属性 赋值是不需要前面加 * 符号的

// 直接指向赋值就可以.. 所以我们在 初始化 结构体的时候一般会 & 取出内存地址
a.Name = "mmmmmm"

匿名结构

简单的匿名结构

func main() {
    a := struct {
        Name string
        Age  int
    }{
        Name: "ailuoy",
        Age:  11,
    }
    fmt.Println(a)
}
{ailuoy 11}

匿名结构的嵌套

同样的,结构体中可以嵌套结构体

type person struct {
    Name string
    Age  int
    Contact struct {
        Phone, City string
    }
}

func main() {
    a := person{Name: "ailuoy", Age: 19}
    a.Contact.Phone = "123123"
    a.Contact.City = "beijing"
    fmt.Println(a)
}
{ailuoy 19 {123123 beijing}}

因为Contact是一个匿名结构,所以我们没办法对他赋值用以下方法来赋值了

a.Contact.Phone = "123123"
a.Contact.City = "beijing"

如果多个参数的值都是一个类型可以写成 Phone, City string

匿名参数

type person struct {
    string
    int
}

func main() {
    a := person{"ailuoy", 19}
    fmt.Println(a)
}
{ailuoy 19}

因为连参数都是匿名的... 所以... 这里初始化的赋值顺序一定不能反.否则会出错

结构体运算 == 和 !==


type person struct {
    string
    int
}

type person1 struct {
    string
    int
}

func main() {
    a := person{"ailuoy", 19}
    b := person1{"ailuoy", 19}
    fmt.Println(a == b)
}
# command-line-arguments
./basic_structure.go:19:16: invalid operation: a == b (mismatched types person and person1)

这里有两个一样的struct除了名字不一样... 但是他们是不能用来做 != 或者 == 的因为名字不一样 也不能算是同一个struct

只有以下的才能做运算

type person struct {
    string
    int
}

func main() {
    a := person{"ailuoy", 19}
    b := person{"ailuoy", 19}
    fmt.Println(a == b)
}
true

struct的继承

go其实是没继承的,, 当时可以用结构体的嵌套方式来间接实现继承.. 但绝不是继承

//充当"基类"
type human struct {
    Sex string
}

type teacher struct {
    human
    Name string
    Age  int
}

type student struct {
    human
    Name string
    Age  int
}

func main() {
    //因为human作为嵌套的时候也算是一个匿名参数,所以必须 human{Sex: "man"}
    t := teacher{Name: "teacher", Age: 10, human: human{Sex: "man"}}
    s := student{Name: "student", Age: 3}
    //同样的Sex会作为没一个结构体的属性, 所以也可以用这种方式来赋值
    s.Sex = "woman"
    fmt.Println(t, s)
}

嵌套过程中出现同名属性

func main() {
    a := A{Name: "A", B: B{Name: "B"}}
    //这首A中有一个B结构体. 所以 要取到B中的Name要a.B.Name
    fmt.Println(a, a.Name, a.B.Name)
}

type A struct {
    B
    Name string
}

type B struct {
    Name string
}
{{B} A} A B

结构体中没有属性, 嵌套有的情况

func main() {
    //因为A中没有Name所以不能写字面
    a := A{B: B{Name: "B"}}
    //这里使用a.Name发现a中没有Name就会忘上找.. 然后就找到了B
    fmt.Println(a, a.Name, a.B.Name)
}

type A struct {
    B
}

type B struct {
    Name string
}
{{B}} B B

同级有重复的属性,必须明确的取.不能让Go去找

func main() {
    a := A{B: B{Name: "B"}, C: C{Name: "C"}}
    fmt.Println(a, a.Name, a.B.Name)
}

type A struct {
    //这里B C是同级的.. 且有相同的属性Name
    B
    C
}

type B struct {
    Name string
}

type C struct {
    Name string
}

# command-line-arguments
./basic_structure.go:8:18: ambiguous selector a.Name
``

>这就导致了 Go不知道你要取哪一个Name了.因为都是同级的.所以就不能用a.Name了这样会找到2个

>所以就必须 a.C.Name, a.B.Name 这样找