青训营后端Go语言基础(五) | 豆包MarsCode AI 刷题

77 阅读5分钟

go语言结构体的初始化

未初始化的结构体,成员都是零值 int 0 float 0.0 bool false string nil

func main(){
    type Person struct{
        in,age int
        name,email string
    }
    var tom Person
    fmt.Println(tom)// 0 0 " " " "
}

使用键值对对结构体进行初始化

func main(){
    type Person struct {
        id,age int
        name,email string
    }
    sk:= Person{
        id: 1,
        name:"sk",
        age: 20,
        email: "sk@elysium.org.cn",
    }
    fmt.Println(sk)//{1,sk, 20, sk@elysium.org.cn}
}

使用值的列表初始化

func main(){
    type Person struct{
        id,age int
        name,email string
        }
    kite:=Person{
        1,
        20,
        "sk",
        "sk@elysium.org.cn"
    }
    fmt.Println(kite)//{1 20 sk sk@elysium.org.cn}
}

注意:

  1. 必须初始化结构体的所有字段
  2. 初始值的填充顺序必须与字段的结构体中的声明顺序一直
  3. 该方式不能和键值初始化方式混用

部分成员初始化

用不到的成员,可以不进行初始化

func main(){
    type Person struct{
        id,age int
        name,email string
    }
    kite:=Person{
        id:1,
        name:"sk"
    }
    fmt.Println(sk)//{1 0 sk " "}
}

go结构体指针

结构体指针和普通的变量指针相同,先来回顾一下普通变量的指针

func main(){
    var name string
    name = "Alex"
    //p_name 指针类型
    var p_name *string
    //&name 取name地址
    p_name= &name
    fmt.Println(name)//tom
    //输出指针地址
    fmt.Println(p_name)//0xcc00010
    //输出指针指向的内容值
    fmt.Println(*p_name)//Alex
}

结构体指针

func main(){
    type Person struct{
        id int
        name string
    }
    var alex = Person{1,"Alex"}
    var p_person Person
    p_person = &alex
    fmt.Println(tom)//{1,alex}
    fmt.Println(p_person)//0xc000001313
    fmt.Println(*p_person)//{1,Alex}
}

使用new关键字创建结构体指针

我们还可以通过使用new关键词对结构体进行实例化,得到的是结构体的地址,例如:

func main(){
    type Person struct{
        id int
        name string
    }
    var p_person = new(Person)
    fmt.Println(p_person)//*main.Person
}

访问结构体指针成员

访问结构体指针成员,也使用点运算符(.),例如:

func main(){
    type Person struct{
        id int
        name string
    }
    var p_person = new(Person)
    fmt.Println(p_person)//*main.Person
    p_person.id=1//等价于*p_person.id
    p_person.name="Alex"
    fmt.Println(*p_person)//{1,Alex}
}

go结构体作为函数参数

go结构体可以像普通变量一样,作为函数的参数,传递给参数,这里分为两种情况:

  1. 直接传递结构体,这是一个副本(拷贝),在函数内部不会改变外面结构体内容
  2. 传递结构体指针,这时在函数内部,能够改变外部结构体内容

直接传递结构体

实例

type Person struct{
    id int
    name string
}
func showPerson(person Person){
    person.id=1
    person.name="Alex"
    fmt.Println(person)
}
func main(){
    person:=Person{1,"Blex"}
    fmt.Printf(person)//{1 Blex}
    fmt.Println("---------")
    showPerson(person){1 Alex}
    fmt.Println("---------")
    fmt.Println(person)//{1 Alex}
}

从运行结果可以看出,函数内部结构了结构体内容,函数外面并没有被改变。

传递结构体指针

实例

type Person struct{
    id int 
    name string
}
func showPerson(person *Person){
    person.id=1
    person.name = "Alex"
    fmt.Println(person)
}
func main(){
    person:=Person{1,"Alex"}
    fmt.Println(person)//{1 Alex}
    fmt.Println("---------")
    showPerson(&person)//{1 Alex}
    fmt.Println("---------")
    fmt.Prinltn(person)//{1 Alex}
}

从运行结果,我们可以看到,调用函数后,参数被改变了

go嵌套结构体

go语言没有面向对象编程思想,也没用继承关系,但是可以通过结构体嵌套来实现这种效果。

下面通过实例演示如何实现结构体嵌套,加入有一个人Person结构体,这个人还养了一个宠物Dog结构体。

下面我们来看一下:

Dog结构体

type Dog struct{
    name string
    color string
    age int
}

Person结构体

type person struct{
    dog Dog
    name string
    age int
}

访问它们

type Dog struct{
    name string
    color string
    age int
}
type person struct{
    dog Dog
    name string
    age int
}
func main(){
    var Alex person
    Alex.dog.name = "旺财"
    Alex.dog.colo = "富贵"
    Alex.dog.age = 2
    Alex.name = "tom"
    Alex.age = 20
    fmt.Println(Alex)//{{旺财 富贵 2} Alex 20}
}

go方法

go语言没有面向对象的特性,也没有类对象的概念。但是,可以使用结构体来模拟这些特性,我们都知道面向对象里面有类方法等概念。

我们也可以声明一些方法,属于某个结构体。

go语言方法的语法

go中的方法,是一种特殊的函数,定义于struct之上(与struct关联,绑定),被称为struct的接收者(receiver)

通俗的讲,方法就是有接收者的函数。

语法的格式如下:

type mytype struct{}
    func(recv mytype) my_method(para) return_type{}
    func(recv *mytype) my_method(para) return_type{}

mytype:定义一个结构体

recv:接受该方法的结构体(receiver)

my_method:方法名称

para:参数列表

return_type:返回值类型

从语法格式看,一个方法和一个函数非常相似,多了一个接受类型

实例

struct Person struct{
        name string
   }
​
func (recv Person) login(name string) bool{
    fmt.Println(recv.name)
    if recv.name==name{
        return true
    }else{
        return false
    }
}
func (rec Person) userName(){
    fmt.Println(rec.name)//Alex
}
func main(){
    var per= Person{"Alex"}
    b:=per.login("Blex")
    per.userName()//Alex
    fmt.Println(b)//false
}

go语言方法的注意事项

  1. 方法的receiver type并非一定要strcut类型,type定义的类型别名,slice,map,channel,func等类型都可以。
  2. struct结合它的方法等价于面向对象中的类。只不过struct可以和它的方法分开,并非一定要属于同一个文件,但必须属于同一个包。
  3. 方法有两种接受类型:(T Type)(T *Type),两者有区别。
  4. 方法就是函数,所有go中没有方法重载(overload)的说法,也就是说同一个类型中的所有方法名必须都唯一。
  5. 如果receiver是一个指针类型,则会自动解除引用
  6. 方法和type是分开的,意味着实例的行为(behavior)和数据存储(field)是分开的,但是它们通过receiver建立起关联联系

方法接收者类型

结构体实例,有值类型和指针类型,那么方法的接收者是结构体,那么也有值类型和指针类型。区别就是接收者是非欧复制结构体副本。值类型复制,指针类型不复制。

值类型和指针类型结构体

type Person struct{
    name string
}
func main(){
    p1:=Person{"tom"}
    fmt.Printf("%T",p1)//main.Person 值类型
    p2:=&Person{"tom"}
    fmt.Printf("%T",p2)//*main.Person 指针类型
}

方法的值类型和指针类型接收者

package main
​
import "fmt"type Person struct {
    name string
}
​
func (recv Person) showPerson() {
    fmt.Printf("%p\n", &recv)
    recv.name = "Alex"
    fmt.Println(recv)
}
func (recv *Person) showPersonTwo() {
    fmt.Printf("%p\n", recv)
    recv.name = "Alex" //等价于*recv.name="Alex"
    fmt.Println(*recv)
}
func main() {
    var p1 = Person{"Alex"}
    fmt.Printf("%p\n", &p1)
    p1.showPerson()
    fmt.Println(p1)
    fmt.Println("-----------")
    var p2 = &Person{"Alex"}
    fmt.Printf("%p\n", p2)
    p2.showPersonTwo()
    fmt.Println(*p2)
}
​

今天就先写到这里了