码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Go常见错误第14篇:过度使用getter和setter方法


    前言

    这是Go常见错误系列的第14篇:过度使用getter和setter方法。

    素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi。

    本文涉及的源代码全部开源在:Go常见错误源代码,欢迎大家关注公众号,及时获取本系列最新更新。

    常见错误和最佳实践

    现状

    写Java或者C++的人,可能会习惯下面的编程模式:

    • 将不希望外部直接访问的类成员变量设置为private私有成员。
    • 在类里定义public的get和set方法,用于外部获取和修改这个成员变量的值。get方法我们叫做getter,set方法叫做setter。

    这是一种数据封装模式,在Java和C++里被广泛使用。

    但是在Go语言里,官方从来没有建议使用getter和setter,我们可以直接访问结构体里的成员变量。

    成员变量的可见性通过结构体标识符首字母大小写以及成员变量首字母大小写来控制到package这个层面。

    • 如果结构体要被其它package使用,那结构体的标识符或者说结构体的名称首字母要大写。
    • 如果结构体的成员要被其它package使用,那结构体和结构体的成员标识符首字母都要大写,否则只能在当前包里使用。

    举个Go标准库里的time.Timer结构体的例子:

    // The Timer type represents a single event.
    // When the Timer expires, the current time will be sent on C,
    // unless the Timer was created by AfterFunc.
    // A Timer must be created with NewTimer or AfterFunc.
    type Timer struct {
    	C <-chan Time
    	r runtimeTimer
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Timer结构体定义如上所示,里面有一个成员变量C用于接收Timer到点后的当前时间。

    Timer和C都是大写,所以我们可以直接在下面的代码里访问Timer里的成员变量C拿到当前时间。

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	// print current time
    	fmt.Println(time.Now())
    
    	// NewTimer creates a new Timer that will send
    	// the current time on its channel after at least duration d.
    	timer := time.NewTimer(5 * time.Second)
    
    	// print current time
    	fmt.Println(<-timer.C)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    上面程序执行结果是:

    2022-11-06 13:07:07.706011 +0800 CST m=+0.000174256
    2022-11-06 13:07:12.709128 +0800 CST m=+5.003141645
    
    • 1
    • 2

    这种写法当然不是Go官方所预期的,因为成员变量C一般来说是不直接对外访问。

    如果C暴露了可以对外访问,那我们甚至修改C的值,导致程序出错。

    尽管不推荐这种写法,但是通过这个例子,我们可以知道如下事实:

    Go标准库里对于结构体里不应该修改的字段,也没有使用getter和setter方法。

    辩证来看

    尽管Go官方没有使用getter和setter,但是从另一方面来说,在一些特定场景下使用getter和setter是有好处的。

    • getter和setter隐藏了内部实现,我们可以自己灵活控制该暴露哪些东西。
    • 如果成员变量的值发生了预期之外的变化,那通过getter和setter,我们可以方便做一些调试,更快发现问题。

    Go语言里如果要使用getter和setter方法,有一些命名规范需要遵循。

    假设我们要对结构体里的成员变量balance增加getter和setter方法,那么规范如下:

    • getter方法应该被命名为Balance(而不是GetBalance)。
    • setter方法应该被命名为SetBalance。
    • 首字母大写是因为要被外部package使用,要大写来保证可见性。

    示例如下:

    currentBalance := customer.Balance()
    if currentBalance < 0 {
        customer.SetBalance(0)
    }
    
    • 1
    • 2
    • 3
    • 4

    总结

    • Java/C++等语言里常用的getter和setter,在Go语言里并不是惯例和规范。
    • 但是如果发现有上面讲到的需要使用到getter和setter的场景,那还是应该使用的,而不是完全不用。
    • getter和setter方法命名参考上面提到的命名规范。

    推荐阅读

    • Go面试题系列,看看你会几题?

    • Go常见错误第1篇:未知枚举值

    • Go常见错误第2篇:benchmark性能测试的坑

    • Go常见错误第3篇:go指针的性能问题和内存逃逸

    • Go常见错误第4篇:break操作的注意事项

    • Go常见错误第5篇:Go语言Error管理

    • Go常见错误第6篇:slice初始化常犯的错误

    • Go常见错误第7篇:不使用-race选项做并发竞争检测

    • Go常见错误第8篇:并发编程中Context使用常见错误

    • Go常见错误第9篇:使用文件名称作为函数输入

    • Go常见错误第10篇:Goroutine和循环变量一起使用的坑

    • Go常见错误第11篇:意外的变量遮蔽(variable shadowing)

    • Go常见错误第12篇:如何破解箭头型代码

    • Go常见错误第13篇:init函数的常见错误和最佳实践

    开源地址

    文章和示例代码开源在GitHub: Go语言初级、中级和高级教程。

    公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

    个人网站:Jincheng’s Blog。

    知乎:无忌。

    福利

    我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。

    关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。

    发送消息「进群」,和同行一起交流学习,答疑解惑。

    References

    • https://livebook.manning.com/book/100-go-mistakes-how-to-avoid-them/chapter-2/
    • https://github.com/jincheng9/go-tutorial/tree/main/workspace/lesson12
  • 相关阅读:
    PostgreSQL 建立一张表到底会产生多少文件
    笔记59:序列到序列学习Seq2seq
    这次我设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架
    100-centos 安装mysql
    114、数据库,核心价值是持久层和数据准确性,复杂的事情不要干
    1584.连接所有点的最小费用
    javaSE - Arrays - 数组的定义与使用
    网络通信——与WEB服务器交换数据(三十)
    高校教务系统登录页面JS分析——长沙理工大学教务系统
    javascript 基本语法(二)
  • 原文地址:https://blog.csdn.net/perfumekristy/article/details/127715222
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号