Golang Go语言中的导出变量命名规则让人头疼
是否包导出居然是靠首字母大小写来区分,写着写着,一个变量想修改为包外可见,居然要修改几十上百个文件。
这是一种什么样的思想....
Golang Go语言中的导出变量命名规则让人头疼
<br>func Function() {<br> function()<br>}<br>
你没有 IDE 么…
ide 就可以不修改文件么?…
函数可以导出结构体的包含关系?…
用编辑器的重构功能重命名,会舒服很多,vscode 下直接 F2
lsp 直接 rename 不就可以了
我并不是说改名很麻烦,我其实抱怨的是,如果在定义处用 public/private 等定义的话,只需要修改一处就好了。但是现在这个 public/private 伴随着每个使用它的地方。有十几个文件使用了它,就要修改十几个文件。并不是说麻烦,而是说太不优美了。
确实,这点同意
虽然不优雅,但只能算个小缺点,毕竟不是很频繁发生的事情。而且,每种语言要说烦都能找出特别烦的地方,哪有完美哦。
问就是大道至简
我今天也简单看了一下 GO, 确实很多语法很不合理, 完全就是为了和其他语言不同而不同, 根本谈不上优化和好用. 但是交叉编译二进制真的是好用, 真的爽. 如果语法能类似 kotlin 或 ts, 那也会舒服很多啊
其实一个成员改变包可见性真的是很常见的事情。
用 IDE 很快就改了,问题不大。能很快改掉的问题都不大。就怕那种改不了的。
确实不太行,一点小事莫名其妙搞个大 pr
如果一个变量,被几十、上百文件引用,这是更大的问题吧
在 Go 里一般习惯尽量用 public ,只有大概率确定不对外可见的才 private 。
因为,不管任何语言,从 public 改成 private 都肯定麻烦,也极少发生。而 private 改成 public 稍常见一点,那么,一开始不确定的你就一律先 public 嘛,从而把需要改的情形减少了 90%,等到稳定之后再看看,看到一些完全没有外部引用的,此时再从 public 改成 private 也不迟。
如果你按照其他编程语言那一套,优先 private ,那肯定麻烦。
包内引用一个变量太多次都有问题了…这算是…一个 student 的 id 还不准包内几十个文件引用?
你没觉得这样太迁就一个语言了么?就为了一个 Go 的首字母大写,就摒弃了封装性原则,这不正是我吐槽的地方么?
Go 特立独行的地方很多,例如 Json 和 Struct 的属性匹配,泛型大家都用 <T> 而 Go 用 [T],错误没有堆栈信息最后还是要出一个包裹的 error ,更不用说各种 if err != nil 的判断了,特别影响业务逻辑的流畅程度。
以 Python 为例,它可能引入一个函数(或直接引入一堆函数),这个函数直接就成为一个本地名称了,也就是说会污染本地变量名,但 Go 引入的是一个包,那个包里的所谓 public 成员,不会直接污染本地名称的,比如引入 fmt, 那么不管 fmt 里面有啥公开成员,都要以 fmt.Print 的形式来使用。
因此,在 Go 里面封装不需要太紧张,污染问题本来就不大。
用 go 多年了,从没遇到过你的烦恼,类库一般写下去的之后就能确定它的可见性了,如果经常需要修改你可能要想想是不是前期系统结构考虑不够周到
如果实在不想修改,加一个公共方法把私有成员映射出来也是一个办法,这种做法在各大类库也比较常见,一般都包含私有和公共结构体部分,如果需要操作私有成员的可以通过特定方法进行操作, 直接将私有成员修改为可见也不是一个推荐的方法,可能会导致一些安全问题.
而且 Go 又不使用 Java 那种传统 OOP 的“继承”关系,因此可见性不需要那么严谨和复杂。
我觉得 golang 在国内之所以火是因为当初 goroutine 实现高并发 IO 的需求很简单,效率也很高
高并发 IO 的需求一度也带热了 Python ( Python 有 asyncio ),但是 Python 一时爽,重构火葬场,Python 很快在 web 领域凉了
尽管如此,golang 还是太简陋了,非常不适用于写业务需求,有地方为了避免变量逃逸甚至会把一个函数写到几千行,完全没必要
同时 goroutine 本身也不是十全十美,它浪费内存已经是众所周知的了
这里推荐感兴趣的了解一下 C# 的 async/await 异步模型,对满足高并发 IO 也非常容易实现,异步之间的通信也不需要 channel 那种额外绕一下的方式,对内存利用率高,运行时得力于 .Net Core 性能越来越好也不再是瓶颈。
C# 早早的实现了跨平台,高级语言也十分特性完备,推荐了解。
注:C# 是 async/await 鼻祖,python 等语言都是从它那里借鉴的
朋友,var A=a ,能看懂吗?
大小写这个还好解决,一个文件夹必须是一个包就很痛苦,没办法把子目录放到一个包下。。。
一楼正解,加个 getter 完事儿。
我个人写了几年都已经习惯了,反正 Go 的重构工具也很方便,自动修改所有引用基本没有不 work 的。然后改变量名的 PR 单独开一个,不和其他的 feature/bugfix 混在一起。
记得 Go 的定位是 Modern C 吧,语法“简陋”在当下是一股清流,除了 Go 还有其他语言的语法和 C 差不多简单吗
你这就属于胡说八道了。
Rust ,还支持 bindgen 自动把 c 语言转 rust ,rust 把 go 爆十条街
据说导出大写是为了可读性,如果是直接导出结构体字段的话,可以加个 get/set
改名改可见是少数事件,读代码是多数事件
往好点想,这样可以让你 review 一遍哪里用了它,毕竟你这引用量非常大。
其实挺理解你这种焦躁感的,感觉问题不是出自 golang 身上。
你说 goroutine 浪费内存就有点耍无赖了,一个协程栈最低 4k ,已经比其他编程语言占用低太多了,很多 jvm 都是一次性分配固定 1m ,你用 go 跑一百万个和用 Java 跑一百万个内存占用跟本不是一个量级,后者基本没办法做到,早就 oom 了,你这属于既让马跑又不让马吃草
一样的好嘛…你其它语言改可视度一样要改全部
不用改那只有原本就用 setter/getter function 才不用改 或着你有用 lombok 导致你有这样的错觉 golang 你照样可以自己写 setter getter
golang 这样虽然丑了点但不是不可以接受 我更喜欢全小写加下划线
改字段名所有语言都要 refactor name 搂
就算没这功能也很好解决 字段唯一的状况一行指令就搞定了 你如果在 vim 底下用 vimgrep 挑选更改也可以 还可以更快点
go 的泛型这个的确是,看着很不舒服
你有发这个帖子的时间拿 IDE 都改完了
情绪这么不稳定还是不要编程了,一个大写导出就“恨死了”,再写下去早晚得抑郁。
如果从 private 改成 public ,不也要改几百个文件?
你这逻辑很不可理喻
不对吧,如果你一开始就是小写,那么必须同一个包才能使用,怎么可能到处都是引用,所以何来到处都要改的问题?那如果你一开始就是大写,现在要改 private ,同等情况就算 python ,java 也要改很多地方(或者借助 idea ,lsp )的 refactory ,所以何来吐槽呢?不要为了吐槽而吐槽啊?
同意,他这种方式是不想写方法,原则上来说,如果要对外能访问,又不想改可见级别,Java 难道不是另开一个方法么? Java 领域也没人敢把 private 的方法直接改成 public 的方法吧
要修改多个文件是因为你改了函数名, 不是因为改了可见性, 虽然这是因为 Go 的可见性和函数名大小写绑定, 按照其他人说的, 如果只是想增加一个导出 API, 又不想修改太多文件, 可以加一个包装函数
语言风格有好处有坏处, 有人能接受, 有人接受不了, 不能接受就换, 换到满意为止
go 本身就是为了工程而生的,各种杂七杂八的限制很多就是为了让大家按一个模子写,方便协作
换语言吧,搞多了你自己心情都要崩溃了
我反而挺喜欢这个根据大小写判断 public 和 private 的, 要不然每个变量前面加个单词 好麻烦, C++ 虽然可以 作用后面全部, 但是有时候还要往前翻才知道到底是 public 和 private
说实话 一般 public 改 private 不管啥语言影响都挺大。 一个 private 改 public 的,能改动几十上百个文件?我的认知里一个 package 咋做到上百个文件的🫠🫠🫠
ide 改简单倒是简单,都是对 code reviewer 实在是太残酷了
我这边建议你换语言呢亲
#38 所以 OP 放弃了 Go. 人们有权表达自己对某个编程语言的厌恶.
没用 (T) 已经很不错了
厌恶可以,恨死就极端了吧。你有见过完美的语言吗?我很想知道 op 或者你换到什么语言了
没用 (T) 已经很不错了
要笑哭了。
恨死了,估计是性格有问题了,,,只是一门语言而已,不喜欢就不用,找工作的时候找自己喜欢的语言的工作就行了呗。
七天速成 Golang 都知道如何进行函数方法包外可见,OP 一点都不看,直接上来开写 🤡
本来不可见的,你是怎么写出上百个文件的
本来可见的,你改完了,本来也要全改一遍
我就觉得函数名大写太丑了所以拒绝学习这门语言
大道至简是这样的😁
吐槽逻辑不成立。
同#41 和#57 ,private 的情况,怎么实现几百个地方都引入的?本来 public 改成 private ,那其他语言外部使用的一样都需要大批量修改,和 go 又有什么区别呢?
无论你吐槽什么,go 粉都有几十种理由解释为什么要这样设计,先进在哪里
这点确实不爽,什么 IDE 重构,一下子修改几十上百个文件,commit 太美了
#61
这是什么逻辑,有人不喜欢就有人喜欢,这不是很正常?
难道你可以吐槽不喜欢,别人就不能表达喜欢吗?
好像是为黑而黑,这种场景本来就很少见。
1. 原来是 private ,你要把它改成 public 。这个时候,原本外面就没有地方使用,你改了以后外面才开始使用。所以没有负担。
2. 原来是 public ,现在改成 private 。如果原来只有少数几个地方使用,改成小写不费力。如果原来有几百个地方使用,你有多大的胆子敢做这样大规模的重构?被几百个地方使用的公共函数,也敢轻易改成私有?
“成员改变包可见性真的是很常见的事情”,这是一开始的设计发生了问题,一两次还好,怎么还是常见的呢?
回到帖子本身的问题,如果一个成员已经是私有,怎么会在多处被引用,然后引发楼主所说的“修改几十个文件”。
短短几句话就暴露了水平,别把 V 站当贴吧。
同一个包难道就不能引用了吗
有没有一种可能,同一个包的不同文件也可以引用
引用私有成员本身就破坏了封装性
定义的地方修改下就行了。不用所有引用的地方修改。
我在包内不能引用么?… 对不起暴露了水平…
修改的时候只用修改一处,不用处处修改
建议换成 JAVA 呢
你和那些语言一样用 struct 不就只用改一处了?要改这么多,难不成你到处写全局变量和全局函数?
修改的时候只用修改一处,不用处处修改
如果是 ide 的话,改变大小写,也只用修改一处。
注意看 op 的描述,几十上百个文件
😁,Go 大道至简是这样的,大小写确定可见性的魅力,还搁着「改可见性的情况很少」,问就是你写的不对。
😅咋不说 Java 有 IDE 的情况下很简洁。凡事要用 IDE 改善的地方,我只能认为设计的垃圾,可见性和名称挂钩是 sb 到极点的设计。
我回答中说的 async await 无栈协程可以做到对内存的高效利用
据我所知 java 里没有 async await ,java 也是吃内存大户(但 kotlin 有 async await )。
也许你会说除了 java 和 go ,其他语言不好招人。但我想说的是:golang 本来也不好招人,吹的人多了,就好招了
你提到的跑一百万个协程的内存与效率问题,可以搜索一下 async 与 goroutine 的对比
不是所有协程都是有栈协程( 4k 的栈大小),async 这种编译时的无栈协程对内存的利用率天然更好
惊了!第一次听说要把 id 改成 ID 的!
只需要新定义 Person.GetId 的方法就能解决的问题,为什么变成要修改几十个文件?
话说一个包下几十个文件,这就是十年服务端的功力吗,涨见识了
关于 code review, 你完全可以把 export id 拆出来, 分 2 次提交, 根本不会有什么问题.
用了快十年才发现这个规则?用了快十年还没习惯 go 特立独行的设计?现在吐槽是不是有点晚
#52 人们亦有权利憎恨一种语言。至于我?我有说过我要换吗?
仔细看,楼主讲的是原本 private 但是有很多包内引用,现在改成 public 这些无辜的包内引用也要跟着改
看了附言。
1. 可以弄个 Person.GetId 方法
2. 一个包分几十个文件,这本身可能就有问题,又不是 Java ,分那么多个文件干嘛,徒增麻烦
3. 从你附言来看,这种改动还是少见的啊,你原本说常见,并不成立
4. 既然少见,顶多算个小问题吧
补充一下我熟悉的其他编程语言的情况
python, 用下划线区别
c++ ,public, private, 但是通常私有成员变量的命名会区别于公开成员变量比如, name, m_name, name
感觉只有 java 是可以直接改吧? 但是 java 也是推荐 get/set.
不太懂你觉得好的语言是哪个?
id 改 ID ,那再加一个 ID()方法是最简单的。GetID()命名不是推荐的 style 。再说 op 是要暴露给外界读,那加一个方法不是本来就是最优设计?
#86 憎恨/恨死了这样的用语可能我用的少,无法共情你们。
不知道你是怎么理解的,我哪里说别人不能表达喜欢了?
刚开始确实很难理解,就像我刚学 rust 的时候就很疑惑为啥其他基本类型是全小写,唯独 String 是大写开头的,后来我才突然意识到 String 不是基本类型而是个对象,char 才是基本类型。
因此你可以这样理解 go 的导出命名规则,大写就相当于是说明导出(对象)而不是内部(基本类型)。
#67
#71
包内引用的情况无需讲明,因为这种情况不会产生“需要修改为 pub 字段的需求”;唯一的可能是在开发过程中,包内的引用相关代码需要提取到包外,这不是说不会发生,而是不会频繁发生。对于楼主的情况,需要提取几十个文件到包外,这已经是处于后期开发进程,并且是对项目的较大更改。
为什么直接加一个 Export 函数不行?
别问, 问就是 大道智减 😅
大小写这个还好,我开发过程中,觉得恶心的有两点,一个就是包,一个文件夹就是一个包,导致我想创建一个 util 包,里面包含 str ,json ,dict 那些公共的工具包,还不行,因为没有重载的概念,导致,util 得创建 str_util ,json_util 这样的文件夹,另外一个就是循环引用的问题
这个 getter/setter 明显就不是 go 的风格
包装一个函数就可以了
func _innerFunc() {…}
func OuterFunc() {
return _innerFunc()
}
这个可以的啊
我曾见一位一开始写 java 的同事,觉得 golang 的 error 设计太繁琐,在公司的业务代码里自己按照 java 那一套封了一个 error handler, 然后被打回让重改。这点上不是 golang 不好用,而是他习惯了其他规则,一上来就觉得不合理,不对,连语言本身特性、设计都懒得去了解和思考
在Go语言中,导出变量的命名规则确实是一个需要适应和理解的方面,但一旦掌握,你会发现这其实是Go语言简洁和一致性设计的一部分。
首先,Go语言通过大小写来控制变量的可见性,这是一个非常直观的设计。如果一个变量的名字以小写字母开头,那么它就是包私有的,只能在定义它的包内部访问。相反,如果变量名以大写字母开头,那么它就是导出的,可以被其他包访问。
这种设计简化了模块间的接口管理,使得开发者可以清晰地知道哪些变量是公开的API,哪些变量是内部实现细节。虽然一开始可能会觉得这种命名规则有些头疼,但实际上它避免了像Java那样需要使用额外的修饰符(如public、private)来声明变量的可见性,从而使代码更加简洁。
为了更好地适应这种命名规则,建议你在编写Go代码时,遵循以下实践:
- 明确区分:对于包内使用的变量,使用小写字母开头;对于需要导出的变量,使用大写字母开头。
- 文档化:在包的文档中清晰地说明哪些变量是导出的,以及它们的作用和用法。
- 一致性:保持命名风格的一致性,这有助于代码的可读性和可维护性。
总之,虽然Go语言的导出变量命名规则可能需要一些时间来适应,但它实际上是一种非常有效和简洁的设计。希望这些建议能帮助你更好地理解和使用Go语言。