7.结构体和方法

自定义类型

在go语言中可以语句基本类型定义一个全新的类型

// 使用type关键字,基于int类型定义一个全新的类型MyInt
type MyInt int

类型别名

给已有的类型起一个别的名字

// 给int类型起一个别名:NewInt
type NewInt = int

结构体

一种可以包含多种其他数据类型的数据类型

定义

使用typestruct来定义结构体:

type 类型名 struct{
  字段名 字段类型
  字段名 字段类型
  ...
}
  • 类型名:在同一个包内不能重复
  • 字段名:在同一个结构体中不能重复
  • 字段类型:表示对用字段的具体类型
type person struct{
  name string
  age int
  city string
}

// 字段类型相同的可以写在同一行
// 在定义时可以将类型相同的定义在一起,节省内存
type person struct{
  name, city string
  age int
}

结构体实例化

type person struct{
  name, city string
  age int
}
// 和声明普通变量一样
// var 变量名称 变量类型
var liming person
liming.name="李明"
liming.age=18
liming.city="北京"

fmt.Println(liming.name)
fmt.Println(liming.age)
fmt.Println(liming.city)

匿名结构体

func main(){
  var lisi struct{
    name string
    age int
  }
  lisi.name = "李四"
  lisi.age=20
}

结构体指针

type person struct{
  name, city string
  age int
}

func main(){
  var han = new(person)
	(*han).name = "韩梅梅"
	(*han).age = 21
	(*han).city = "上海"
  // 在go语言中提供了语法糖,对于指针类型的结构体,可以不取值,直接操作
  han.name = "韩梅梅2"
  han.age = 22
  han.city = "浦东"
}

取结构体的地址进行实例化

type person struct{
  name, city string
  age int
}

func main(){
  p:=&person{}
  fmt.Printf("%T\n", p3) // *person
  fmt.Printf("%v\n", p3) //&{name:"",city:"",age:0}
  p.name="人"
}

结构体的初始化

type person struct{
  name, city string
  age int
}
func main(){
  // 1.键值对初始化
  p1:=person{
    name:"小王",
    city:"北京"
    // age:19 // 可以少字段,没有赋值的字段就是对应字段类型的零值
  }
  
  // 2.值的列表进行初始化(不推荐),要与定义结构体时的顺序一一对应,且不可以少字段
  p2:=person{
    "老王",
    "北京"
    "12"
  }
}

结构体构造函数

其实就是写一个函数来构造结构体实例

因为结构体是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以一般构造函数返回的是结构体指针类型

func newPerson(name,city string, age int)*person{
  return &person{
    name:name
    city:city
    age:age
  }
}

func main(){
  p := newPerson("王子", "北京", 18)
}

方法和接收者

方法是一种特定类型变量的函数,这种特定类型变量叫做接收者。接收者的概念类似于其他语言的thisself

func (接收者变量名称 接收者类型) 方法名 (参数列表)(返回参数){
  函数体
}
  • 接收者变量名称:官方建议是有接收者类型名的第一个小写字母,例如:Person类型的接收者变量应命名为P。
  • 接收者类型:和参数类型类似,可以是指针类型和非指针类型
  • 方法名、参数列表、返回参数:于函数定义时相同

例:

// Person 是一个结构体
type Person struct{
  name string
  age int
}
// NewPerson 是一个Person类型的构造函数
func NewPerson(name string, age int)*Person{
  return &Person{
    name:name,
    age:age,
  }
}
// Dream 是为Person类型定义的方法
func (p Person)Dream(){
  fmt.Pringf("%s的梦想是学好go语言", p.name)
}

// SetAge 是一个修改年龄的方法,指针接收者指的是接收者的类型是指针
func (p *Person)SetAge(newAge int){
  p.age = newAge
}

// SetAge2是一个使用值接收者来修改年龄的方法
func (p Person) SetAge2(newAge int){
  p.age = newAge
}

func main(){
  p1:=NewPerson("小李", 19)
  p1.Dream()
  p.SetAge()// 使用指针接收者修改后,可以修改接收者的值
  p.SetAge2()// 这里修改后,p.age不会变化,因为是值拷贝
}

什么时候应该使用指针类型

  1. 需要修改接收者的中的值
  2. 接收者是拷贝代价比较大的大对象
  3. 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接受者
posted @ 2025-06-20 14:32  L大官  阅读(6)  评论(0)    收藏  举报