• GO语言实战之嵌入类型和属性隐私定义


    写在前面


    • 嗯,学习GO,所以有了这篇文章

    • 博文内容为《GO语言实战》读书笔记之一

    • 主要涉及知识

      • 嵌入类型
      • 隐私性标识符的作用
    • 理解不足小伙伴帮忙指正

    对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔曼·黑塞《德米安》


    嵌入类型

    Go 语言 允许用户扩展或者修改已有类型的行为。在修改已有类型以符合新类型的时候也很重要。这个功能是通过 嵌入类型(type embedding) 完成的,嵌入类型是将已有的类型直接声明在新的结构类型里。被嵌入的类型被称为新的外部类型的内部类型

    通过嵌入类型,与内部类型相关的标识符会提升到外部类型上

    这里嵌入类型,即有面向对象中继承的味道,内部类的相关标识会提升到外部类型上,即类似面向对象中的继承,子类会继承父类的方法和属性。会涉及到重写隐藏

    golang 本质上是没有继承相关语法和概念,相对于 Java 来讲,不同的是 支持多继承,可以同时嵌入多个内部类型。而且外部类型也没有对内部类型的引用。没有 super 的概念. 在整体设计上,有种 Java 内部类继承了一个和外部类无关的类的感觉

    本质上 嵌入类型是一种组合关系,合成复用原则,没有继承那种强关系。

    package main
    
    import (
     "fmt"
    )
    type user struct {
     name  string
     email string
    }
    
    type user1 struct {
     name1 string
     name2 string
    }
    
    func (u *user) notify() {
     fmt.Printf("Sending user email to %s<%s>\n",
      u.name,
      u.email)
    }
    type admin struct {
     user  // Embedded Type
     user1
     level string
    }
    func main() {
     ad := admin{
      user: user{
       name:  "john smith",
       email: "john@yahoo.com",
      },
      level: "super",
     }
     ad.user.notify()
     // 借助内部类型提升,notify 方法也可以直接通过 ad 变量来访问
     ad.notify()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    直接通过外部类型的变量来调用 notify 方法,由于内部类型的标识符提升到了外部类型,我们可以直接通过外部类型的值来访问内部类型的标识符,类似面向对象中的继承

    func main() {
     ad := admin{
      user: user{
       name:  "john smith",
       email: "john@yahoo.com",
      },
      level: "super",
     }
    
     sendNotification(&ad)
    }
    
    func sendNotification(n notifier) {
     n.notify()
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果外部类型并不需要使用内部类型的实现,就需要重写,在外部类型中重写内部类型的绑定的方法,这对于内部类型被称之为隐藏

    package main
    
    import (
     "fmt"
    )
    
    type notifier interface {
     notify()
    }
    type user struct {
     name  string
     email string
    }
    func (u *user) notify() {
     fmt.Printf("Sending user email to %s<%s>\n",
      u.name,
      u.email)
    }
    type admin struct {
     user
     level string
    }
    func (a *admin) notify() {
     fmt.Printf("Sending admin email to %s<%s>\n",
      a.name,
      a.email)
    }
    func main() {
     ad := admin{
      user: user{
       name:  "john smith",
       email: "john@yahoo.com",
      },
      level: "super",
     }
     sendNotification(&ad)
     ad.user.notify()
     ad.notify()
    }
    func sendNotification(n notifier) {
     n.notify()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    公开或未公开的标识符

    要想设计出好的 API,需要使用某种规则来控制声明后的标识符的可见性。Go 语言支持包里公开或者隐藏标识符,让用户能按照自己的规则控制标识符的可见性

    • 当一个标识符的名字以小写字母开头时,这个标识符就是未公开
    • 如果一个标识符以大写字母开头,这个标识符就是公开的,
    package counters
    
    type alertCounter int
    
    • 1
    • 2
    • 3

    对于未公开的属性,赋值可以使用类似工厂函数的方式

    package counters
    
    type alertCounter int
    
    func New(value int) alertCounter {
     return alertCounter(value)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    也可以使用 setter 方法

    type User struct {
      id int
      name string
    }
    
    func (u *User) SetName(name string) {
      u.name = name
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    User 类型被声明为公开的类型。User 类型里声明了两个字段,一个名为 Name 的公开的字段,一个名为 email 的未公开的字段

    package entities
    
    // User defines a user in the program.
    type User struct {
     Name  string
     email string
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    func main() {
     u := entities.User{
      Name:  "Bill",
      email: "bill@email.com",
     }
     fmt.Printf("User: %v\n", u)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    试图初始化未公开的字段 email,所以编译器抱怨这是个未知的字段。因为 email 这个标识符未公开,所以它不能在 entities 包外被访问

    公开和未公开的内嵌类型是如何赋值的

    package entities
    
    // user 在程序里定义一个用户类型
    type user struct {
     Name  string
     Email string
    }
    
    // Admin 在程序里定义了管理员
    type Admin struct {
     user   // 嵌入的类型未公开
     Rights int
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    内嵌类型初始化

    func main() {
     // / 创建 entities 包中的 Admin 类型的值
     a := entities.Admin{
      Rights: 10,
     }
    
     // 设置未公开的内部类型的
     // 公开字段的值
     a.Name = "Bill"
     a.Email = "bill@email.com"
    
     fmt.Printf("User: %v\n", a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    博文部分内容参考

    © 文中涉及参考链接内容版权归原作者所有,如有侵权请告知.


    《GO语言实战》


    © 2018-2023 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

  • 相关阅读:
    多线程互斥锁 pthread_mutex 的使用及初始化问题
    开放式运动耳机排行榜,盘点五款最适合入手的运动耳机
    手把手带你刷好题(牛客刷题④)
    web课程设计网页规划与设计 基于HTML+CSS美食网站设计与实现(6个页面)
    vite源码分析之dev
    在微信小程序里引入Vant Weapp组件库详细步骤
    GDB之调试系统接口syscall(九)
    基于php 进行每半小时钉钉预警
    C++—多态
    SetUp
  • 原文地址:https://blog.csdn.net/sanhewuyang/article/details/133279643