2021/04/07关于go中的继承和空结构体

GO在文档中强调了根本没有继承这一概念

1.屏蔽现象

一个简单的demo

package main

import (
    "fmt"
)

var name = 11
func main(){
    var name =10
    {
        var name = 9
        fmt.Println(name)
    }
    fmt.Println(name)

}

结果很明显,输出9,10

根据对作用域的理解,程序实体的访问权限由代码块控制,变量也属于程序实体, 嵌套的代码块导致变量出现被屏蔽的现象。这称为变量的屏蔽现象

那函数呢?

package main

import (
    "fmt"
)

type AnimalCategory struct {
    kingdom string // 界。
    phylum  string // 门。
    class   string // 纲。
    order   string // 目。
    family  string // 科。
    genus   string // 属。
    species string // 种。
}


func (ac AnimalCategory) String() string {
    return fmt.Sprintf("hi%s%s%s%s%s%s%s",
        ac.kingdom, ac.phylum, ac.class, ac.order,
        ac.family, ac.genus, ac.species)
}


type Animal struct {
    scientificName string // 学名。
    AnimalCategory        // 动物基本分类。这里嵌入其他结构体
}


func (a Animal) String() string {
    return fmt.Sprintf("%s (category: %s)",
        a.scientificName, a.AnimalCategory)
}

func main(){
    category := AnimalCategory{species: "cat"}
    fmt.Printf("The animal category: %s\n", category)
    animal := Animal{
        scientificName: "American Shorthair",
        AnimalCategory: category,
    }
    fmt.Printf("The animal: %s\n", animal)
}

我们发现在执行 main函数中的打印函数时,虽执行了Animal结构体的String方法,但是Animal中的String方法执行a.AnimalCategory的字符串时,并没有执行
AnimalCategory结构体定义的string方法,也就是说出现了同名函数的遮蔽现象。(Animal 内嵌结构体 AnimalCategory )

也就是说,虽然AnimalCategory利用嵌入字段,但是同名的方法还是会被覆盖(内嵌结构体的同名方法不会被执行)。
通过这个例子也就明白了Go中并没有继承的概念,Go语言利用了嵌入字段的特性,使得“子类”能够坐享其成的使用“父类”(嵌入结构体)的一切,即使某些方法不合心意,还可以利用屏蔽特性进行“方法的重写”去调整优化

2.空结构体

空结构体不占用空间

package main

import (
    "unsafe"
)

func main(){
    var a = struct{}{}
    var b = 1
    fmt.Printf("%d,%d",unsafe.Sizeof(a),unsafe.Sizeof(b))
}

既然不占用内存,那么我们就可以把他当作是js的undefined的占位符(这里描述不准确,undefined为一个变量,大致类比一下)来使用,比如利用map和空结构体来实现set

package main

import (
    "fmt"
)
type Set map[string]struct{}
func (set Set) Has(s string) bool{
    _,ok := set[s]
    return ok
}
func (set Set) Add(s string) {
    if ok := set.Has(s);!ok{
        set[s] = struct{}{}
    }
}

func (set Set) Del(s string){
    delete(set,s)
}

func main(){
    set := Set{}
    fmt.Println(set.Has("a"))
    set.Add("a")
    fmt.Println(set.Has("a"))
    set.Del("a")
    fmt.Println(set.Has("a"))
}

实现不发送数据的通道,仅通知子协程执行任务

func worker(ch chan struct{}) {
    <-ch //协程阻塞,有struct时执行任务
       // TODO
    fmt.Println("do something")
    close(ch)
}

func main() {
    ch := make(chan struct{})
    go worker(ch)
    ch <- struct{}{}
}

实现仅包含方法的结构体 这里不再做赘述

本文内容及代码参考:

  1. GO核心36讲
    2.GO空结构体的使用

你可能感兴趣的:(2021/04/07关于go中的继承和空结构体)