Go语言面向对象

11次阅读
没有评论

共计 2808 个字符,预计需要花费 8 分钟才能阅读完成。

Go 不是纯粹的面向对象语言,和传统的面向对象编程有区别,所以说 Go 语言支持面向对象编程特性是比较准确的。

Go 语言基于结构体 struct 来实现 OOP 特性,通过 type 和 struct 关键字声明结构体,格式如下:

type 类型名 struct { // 类型名在同一个包内不能重复
  字段 1 字段 1 类型 // 字段名必须唯一
  字段 2 字段 2 类型
}

结构体从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,可以认为结构体是一种聚合类型。

结构体实例化

声明结构体变量再赋值:

type Student struct {
  sid    int      // 字段首字母小写,类似 private,其它包不能使用
  course []string // 选修课程}

func main() {
  // 声明一个结构体对象,值类型,默认开辟空间,字段赋予零值
  var s Student
  fmt.Println("s:", s) // s: {0 []}
  // 访问结构体成员使用点号 . 操作符
  fmt.Println(s.sid) // 0
  // 更改成员变量值
  s.sid = 1001
  fmt.Println(s.sid) // 1001

  // 方式 2:键值对赋值
  s2 := Student{sid: 1002, course: []string{"chinese", "math"}}
  fmt.Println(s2)
  // 方式 3:多值赋值
  s3 := Student{1003, []string{"chinese", "math"}}
  fmt.Println(s3)
}

实例化之 & 结构体:

func initSid(s *Student) {s.sid = 1001 // 其实是 (*s).sid = 1001
}

func main() {s := Student{course: []string{"chinese", "math"}}
  initSid(&s)
  fmt.Println(s) // {1001 [chinese math]}

  s2 := &Student{course: []string{"chinese", "math"}}
  initSid(s2)
  fmt.Println(s2) // &{1001 [chinese math]}
}

实例化之 new(结构体):

func main() {s := new(Student) // 等同于 &Student{}
  fmt.Println(s)    // &{0 []}
}

模拟构造函数

Go 语言没有构造函数,但可以使用结构体初始化过程来模拟实现构造函数(首字母大写)。

// 自定义工厂函数,返回局部变量地址
func NewStudent(sid int, course []string) *Student {
  return &Student{
    sid:    sid,
    course: course}
}

func main() {s := NewStudent(1001, []string{"math", "english"})
  fmt.Println(s) // &{1001 [math english]}
}

方法接收器

Go 语言中的方法(Method)是一种作用于特定类型变量的函数,这种特定类型变量叫做接收者(Receiver)。方法与函数的区别是,函数不属于任何类型,方法属于特定类型。

func (s Student) learn() {fmt.Printf("%d 正在学习...", s.sid)
}

func main() {s := NewStudent(1001, []string{"math", "english"})
  s.learn()}

接收者是指针类型:

type Player struct {
  Name        string
  HealthPoint int
}

func NewPlayer(name string, hp int) *Player {
  return &Player{
    name,
    hp,
  }
}

func (p *Player) attack() {fmt.Printf("%s 发起攻击!\n", p.Name)
}

func (p *Player) attacked() {fmt.Printf("%s 被攻击!\n", p.Name)
  p.HealthPoint -= 10
  fmt.Println("HealthPoint:", p.HealthPoint)
}

func main() {player := NewPlayer(" 张三 ", 100)
  player.attack()
  player.attacked()}

匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段称为匿名字段。

type Person struct {
  string // 其实是 string string
  int    // 其实是 int int
}

func main() {
  p := Person{
    " 张三 ",
    18,
  }
  fmt.Println(p.string, p.int) // 张三 18
}

结构体也可以作为匿名字段使用:

type Addr struct {
  province string
  city     string
}

type Person struct {
  string
  int
  Addr // 其实是 Addr Addr
}

func main() {
  p := Person{
    " 张三 ",
    18,
    Addr{" 广东 ", " 深圳 "},
  }
  fmt.Println(p.Addr.province, p.city) // 广东 深圳
}

当结构体中有和匿名字段相同字段时,采用外层优先访问原则。

包和封装

每个目录一个包,main 包包含可执行入口。

为结构定义的方法必须放在同一个包内,可以是不同文件。

结构体继承

// Animal 动物
type Animal struct {name string}

func (a *Animal) eat() {fmt.Printf("%s is eating!\n", a.name)
}

// Dog 类型
type Dog struct {
  Kind    string
  *Animal // 通过嵌套匿名结构体实现继承,直接写类型,没有字段名
}

func (d *Dog) bark() {fmt.Printf("%s is barking ~\n", d.name)
}

func main() {
  d := &Dog{
    Kind: " 金毛 ",
    Animal: &Animal{ // 注意嵌套的是结构体指针
      name: " 旺财 ",
    },
  }
  d.eat()
  d.bark()}

结构体标签

type Stu struct {
  Name string `json:"name"` // 结构体标签
  Age  int    `json:"-"`    // 表示不参与序列化
}

func main() {stuStruct := Stu{Name: " 张三 ", Age: 18}

  // 序列化
  jsonStuStruct, _ := json.Marshal(stuStruct)
  fmt.Println(string(jsonStuStruct)) // {"name":" 张三 "}

  // 反序列化
  var StuStruct Stu
  err := json.Unmarshal(jsonStuStruct, &StuStruct)
  if err != nil {return}
  fmt.Println(StuStruct) // {张三 0}
}

正文完
post-qrcode
 0
三毛
版权声明:本站原创文章,由 三毛 于2024-02-22发表,共计2808字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)