首页 > 其他分享 >go语言方法之封装

go语言方法之封装

时间:2024-06-05 17:29:46浏览次数:14  
标签:封装 语言 IntSet 类型 func go buf struct

        一个对象的变量或者方法如果对调用方是不可见的话,一般就被定义为“封装”。封装有时也叫信息隐藏,同时也是面向对象编程的一个方面。

        Go语言只有一种控制可见性的手段:大写首字母的标识符会从定义它们的包中被导出,小写的字母则不会。这种限制包内成员的方式同样适用于struct或者一个类型的方法。因而如果我们箱套封装一个对象,我们必须将其定义为一个struct。

        这也就是前面的小节中IntSet被定义为struct类型的原因,尽管它只有一个字段:

type IntSet struct {
    words []uint64
}

        当然,我们也可以把IntSet定义为一个slice类型,尽管这样我们就需要把代码中所有方法里用 到的s.words用*s替换掉了:

type IntSet []uint64

        尽管这个版本的IntSet在本质上是一样的,他也可以允许其它包中可以直接读取并编辑这个 slice。换句话说,相对*s这个表达式会出现在所有的包中,s.words只需要在定义IntSet的包 中出现。

        这种基于名字的手段使得在语言中最小的封装单元是package,而不是像其它语言一样的类 型。一个struct类型的字段对同一个包的所有代码都有可见性,无论你的代码是写在一个函数 还是一个方法里。

        封装提供了三方面的优点。

        首先,因为调用方不能直接修改对象的变量值,其只需要关注少 量的语句并且只要弄懂少量变量的可能的值即可。

        第二,隐藏实现的细节,可以防止调用方依赖那些可能变化的具体实现,这样使设计包的程 序员在不破坏对外的api情况下能得到更大的自由。

        把bytes.Buffer这个类型作为例子来考虑。这个类型在做短字符串叠加的时候很常用,所以在 设计的时候可以做一些预先的优化,比如提前预留一部分空间,来避免反复的内存分配。又 因为Buffer是一个struct类型,这些额外的空间可以用附加的字节数组来保存,且放在一个小 写字母开头的字段中。这样在外部的调用方只能看到性能的提升,但并不会得到这个附加变 量。Buffer和其增长算法我们列在这里,为了简洁性稍微做了一些精简:

type Buffer struct {
    buf []byte
    initial [64]byte
    /* ... */
}
// Grow expands the buffer's capacity, if necessary,
// to guarantee space for another n bytes. [...]
func (b *Buffer) Grow(n int) {
    if b.buf == nil {
        b.buf = b.initial[:0] // use preallocated space initially
    }
    if len(b.buf)+n > cap(b.buf) {
        buf := make([]byte, b.Len(), 2*cap(b.buf) + n)
        copy(buf, b.buf)
        b.buf = buf
    }
}

        封装的第三个优点也是最重要的优点,是阻止了外部调用方对对象内部的值任意地进行修 改。因为对象内部变量只可以被同一个包内的函数修改,所以包的作者可以让这些函数确保 对象内部的一些值的不变性。比如下面的Counter类型允许调用方来增加counter变量的值,并 且允许将这个值reset为0,但是不允许随便设置这个值:

type Counter struct { n int }
func (c *Counter) N() int { return c.n }
func (c *Counter) Increment() { c.n++ }
func (c *Counter) Reset() { c.n = 0 }

        只用来访问或修改内部变量的函数被称为setter或者getter,例子如下,比如log包里的Logger 类型对应的一些函数。在命名一个getter方法时,我们通常会省略掉前面的Get前缀。这种简 洁上的偏好也可以推广到各种类型的前缀比如Fetch,Find或者Lookup。

package log
type Logger struct {
    flags int
    prefix string
    // ...
}
func (l *Logger) Flags() int
func (l *Logger) SetFlags(flag int)
func (l *Logger) Prefix() string
func (l *Logger) SetPrefix(prefix string)

        Go的编码风格不禁止直接导出字段。当然,一旦进行了导出,就没有办法在保证API兼容的 情况下去除对其的导出,所以在一开始的选择一定要经过深思熟虑并且要考虑到包内部的一 些不变量的保证,未来可能的变化,以及调用方的代码质量是否会因为包的一点修改而变 差。

        封装并不总是理想的。 虽然封装在有些情况是必要的,但有时候我们也需要暴露一些内部内 容,比如:time.Duration将其表现暴露为一个int64数字的纳秒,使得我们可以用一般的数值 操作来对时间进行对比,甚至可以定义这种类型的常量:

const day = 24 * time.Hour
fmt.Println(day.Seconds()) // "86400"

        另一个例子,将IntSet和本章开头的geometry.Path进行对比。Path被定义为一个slice类型, 这允许其调用slice的字面方法来对其内部的points用range进行迭代遍历;在这一点上,IntSet 是没有办法让你这么做的。

        这两种类型决定性的不同:geometry.Path的本质是一个坐标点的序列,不多也不少,我们可 以预见到之后也并不会给他增加额外的字段,所以在geometry包中将Path暴露为一个slice。 相比之下,IntSet仅仅是在这里用了一个[]uint64的slice。这个类型还可以用[]uint类型来表 示,或者我们甚至可以用其它完全不同的占用更小内存空间的东西来表示这个集合,所以我 们可能还会需要额外的字段来在这个类型中记录元素的个数。也正是因为这些原因,我们让 IntSet对调用方透明。

标签:封装,语言,IntSet,类型,func,go,buf,struct
From: https://blog.csdn.net/qq_37278522/article/details/139412086

相关文章

  • Golang初学:一些第三方包
    goversiongo1.22.1-- Web开发gorillahttps://gowebexamples.com中的示例有用到。 Routing(usinggorilla/mux)goget-ugithub.com/gorilla/mux-Sessions"github.com/gorilla/sessions"-Websockets$gogetgithub.com/gorilla/websocket- gingoget......
  • c# MongoDB.Driver 连接mongo 数据库失败的解决方法
    在连接数据库的时候连接本的的时候连接字符串是mongodb://localhost:端口号(默认27017)/数据库名(选填)用这种格式的连接字符串去做本地的测试是没问题的,但是连接服务器上面的数据库的时候就要加上用户名和密码,这个时候就需要在字符串的末尾添加后缀:mongodb://用户名:密码(都不......
  • 使用C语言实现链式栈
    一、栈的基本概念        栈(Stack)是一种数据结构,它遵循“后进先出”(LIFO,LastInFirstOut)的原则。这意味着最后一个插入栈的元素最先被删除,你可以理解成一堆盘子,每次只能取最上面的盘子,删除的时候也只能删除最上面的盘子。这样是不是更容易理解了呢?栈的基本操作包......
  • 2024-06-05:用go语言,给定三个正整数 n、x 和 y, 描述一个城市中由 n 个房屋和 n 条街道
    2024-06-05:用go语言,给定三个正整数n、x和y,描述一个城市中由n个房屋和n条街道连接的情况。城市中存在一条额外的街道连接房屋x和房屋y。需要计算对于每个街道数(从1到n),有多少房屋对满足从一个房屋到另一个房屋经过的街道数正好为该街道数。在结果数组中,索引k对......
  • 赛博斗地主——使用大语言模型扮演Agent智能体玩牌类游戏。
    通过大模型来实现多个智能体进行游戏对局这个想对已经比较成熟了无论是去年惊艳的斯坦福小镇还是比如metaGPT或者类似的框架都是使用智能体技术让大模型来操控,从而让大模型跳出自身“预测下一个token”的文字功能去探索更多的应用落地可能性。不过一直没有真正操作过,直到前段时间......
  • 贴片电阻封装尺寸大全
    贴片电阻的封装尺寸有很多种,以下是一些常见的封装尺寸及其对应的英制表示法、公制表示法和功率:0201封装(英制):尺寸为0.6mmx0.3mm。这是最小的贴片电阻封装之一,通常用于高密度电子装配。其对应功率为1/20W。0402封装(英制):尺寸为1.0mmx0.5mm。适用于有限的空间和尺寸要求,对应功......
  • 【C语言】文件操作强化
    【C语言】文件操作强化文章目录【C语言】文件操作强化前言一、文件打开关闭文件打开(fopen)文件关闭(fclose)二、文件读写函数字符读写函数行读写函数块读写函数格式化读写函数随机读写函数三、文件读写注意事项四、配置文件读写案例总结前言本篇文章我们将详细......
  • Exp-Golomb指数哥伦布码
    Exp-Golomb指数哥伦布码指数哥伦布码(Exponential-Golomb)属于熵编码,属于无损编码H.264中使用的是0阶指数哥伦布编码,编码方式如下:以待编码码号code_num=3为例:第一步:将code_num+1,即3+1=4第二步:将4写为二进制的形式:100第三步:计算100的比特个数为3,在100前面写(3-1)个0,得到......
  • golang使用OpenCC繁简转换
    https://github.com/longbridgeapp/openccmain.gopackagemainimport( "fmt" "log" "github.com/longbridgeapp/opencc")funcmain(){ s2t,err:=opencc.New("s2t") iferr!=nil{ log.Fatal(err) } in:=`......
  • 大语言模型应用指南:三类微调方法
    大语言模型应用指南:三类微调方法1.背景介绍1.1大语言模型的发展历程近年来,随着深度学习技术的快速发展,大语言模型(LargeLanguageModels,LLMs)在自然语言处理领域取得了显著的进展。从GPT-2、BERT到GPT-3、PaLM等,大语言模型的规模和性能不断提升,展现出了强大的语言......