写了几个月的业务了 写 err 真的吐了 牵扯到序列 /反序列话、有任何文件、io 操作的地方都会有 error
报的那么多 error 有啥用? 报那么多 error 没能解决问题 第一行成功 下面的几处 error 第一行的 error 岂不是白打了? 这种与业务无强关联的地方 与业务嵌套这么深 直接全局异常捕捉不就行了?
还有都 21 世纪了 居然不支持重载 输出一样 输入参数不一样 不能重载 就很无语。我写个方法功能一样 还得另外起个名字
这群设计者是学术界呆太久了?
101
hutoer 2021-12-26 09:58:50 +08:00
@cmdOptionKana 那你看看 golang make 的用法:
make(map[string]string) make([]int, 2) make([]int, 2, 4) 按照你说的风格,要是变成多个函数了,会不会被吐槽? |
102
cmdOptionKana 2021-12-26 10:01:13 +08:00
@hutoer 当然,我第一次听这种说法的时候,也是愕然了一下,但人家说的是有点道理。
说个题外话,另外一个 Go 语言相关的更震惊我说法是:语法高亮没有必要。 Rob Pike 平时使用一个自己做的编辑器“Acme”是不带语法高亮的,Go 团队里的另一个重要人物 Russ Cox 也使用 Acme 。事实上,可能有些人甚至没有察觉,Go 的文档服务 godoc (现在已迁移到 go.dev )里的示例代码全都没有语法高亮,但只要脑子里想的是如何解决问题,就会发现没有语法高亮一点影响都没有,甚至都忘记了自己看的代码是没有高亮的。 我自己的感受是,看代码时确实语法高亮的影响很小,但自己写代码时高亮还是有明显的辅助作用。 |
103
cmdOptionKana 2021-12-26 10:04:57 +08:00
@hutoer make 选择这种类似重载的风格,主要因为这种自带函数有一半“占据关键词”的副作用,因此才不得不减少函数名。而在 strings, sort 之类的标准库里,就选择了显性的风格。
|
104
cmdOptionKana 2021-12-26 10:07:04 +08:00
@hutoer 要不是怕占了关键词(保留词),换成多个函数名反而更好(从 Go 的审美角度看),我并不觉得会被骂(唯一被骂的理由只是占了保留词)。
|
105
hutoer 2021-12-26 10:38:50 +08:00
@cmdOptionKana 我倒是觉得重载能降低心智负担、提升代码简洁渡,例如:
data := make([]int, 2) data := make([]int, 2, 4) 比下面的简洁 data := makeXX1([]int, 2) data := makeXX2([]int, 2, 4) 还有这种( Color 是构造函数) color = new Color(0,0,255) color = new Color("#FFFFFF") color = new Color(Color::RED) 比下面的简洁 color = new Color() color.setByRGB(0,0,255) color = new Color() color.setByHEX("#FFFFFF") color = new Color() color.setByName(Color::RED) |
106
LUO12826 2021-12-26 10:47:51 +08:00 1
想到以前讨论谷歌 material design 和 iOS 的设计风格时,某乎上有人大篇幅论述谷歌的右划侧边栏是如何比 iOS 的底部 tab bar 优秀的。然而后来,谷歌自己又加上了底部 tab bar
|
107
cmdOptionKana 2021-12-26 11:05:22 +08:00
这个不需要重载啊,变长参数就可以了。
data := make([]int, 2) data := make([]int, 2, 4) 而这个 color = new Color(0,0,255) color = new Color("#FFFFFF") Go 的习惯是 c = color.New(0,0,255) c = color.ByHex("#FFFFFF") 从简洁的角度看差别不大。 (其中 color 是 package 名字,New 和 ByHex 是 public 函数) |
108
aloxaf 2021-12-26 13:48:37 +08:00
@hutoer #99
这个例子举得不好,换我我肯定不会这么设计——「 Color::Color("#FFFFFF")」这种,显然是可能初始化失败的。如果并作一个 API ,在强迫你显式处理错误的语言中,就不得不为明明不可能出错的逻辑写上错误处理代码。 举个我觉得比较常见的「重载」更好的例子: string.replace('a', 'b') string.replace("abc", 'a') string.replace("abc", "def") string.replace("abc", a_function_pointer) ...(以下省略若干种排列组合)... |
110
maja 2021-12-26 14:22:12 +08:00
噗
call/cc 用过没? 这玩意比宁那全局异常捕捉靠谱多了。 |
111
hutoer 2021-12-26 14:33:49 +08:00
@cmdOptionKana golang make 会根据第一个参数做不同的处理,行为更像重载,变长参数不行。
另外,变长参数我反倒觉得是不良设计,尽量少用。 你说的 color.ByHex("#FFFFFF")这种方式,已经是牺牲可读性换取简洁性了。相对我的例子,还不是 OOP 的方式。 其实,我只是想说重载是有用的,而不是想证明没有重载不行。 |
112
Buges 2021-12-26 14:54:18 +08:00 via Android
@hutoer go 的 make 只是缺乏泛型的 trick ,没啥好说的。
另外不要被 OOP 荼毒太深,constructor 本身就是糟粕,可读性简洁性都不如直接用函数。 Color::from_rgb(u8,u8,u8)和 Color::from_hex(String)返回类型都不一样,后者是可失败的(虽然在异常的语言中被隐藏了),难道该用同一个名字吗? 另外就算需要所谓的“重载”效果,用泛型是更好的选择。Color::from<T: Into<Color>>(t:T)->Color 甚至比你写多个重载的函数更“OOP”。 |
113
sxfscool 2021-12-26 15:35:51 +08:00
非要和 java 一样么?为什么不去用 java
|
114
james122333 2021-12-26 15:42:06 +08:00
|
115
hutoer 2021-12-26 16:01:17 +08:00
@Buges Color::from_rgb(u8,u8,u8)和 Color::from_hex(String)返回类型咋不一样了?都是 Color 实例呀。
泛型替代不了重载 至于“constructor 本身就是糟粕,可读性简洁性都不如直接用函数”,这个我就不讨论了,大家看问题的面不一样。 |
116
Buges 2021-12-26 16:31:49 +08:00 via Android
@hutoer 因为后者可能会失败。粗略地说,前者返回 Color ,后者返回 Color | ParseError 。异常的语言可能会隐藏这一点,但用了 checked exception 同样可以体现出来。
泛型就是达到“重载”的效果最合适的方式,泛型代替不了重载的地方就不该用重载。 constructor 完全是多余的复杂度,这个概念根本就没有必要。new FancyClassName(params) 比 FancyClassName.new(params) 没有任何优势。反而让代码难读又难写。如: FancyClassName FancyClassName::FancyClassName(params){ blabla... } |
117
hutoer 2021-12-26 17:08:45 +08:00
@Buges “后者返回 Color | ParseError”,这个说法不恰当,返回的还是 Color ,Parse 出错只不过抛异常。
前者函数内出错误( Color 这例子简单,大面上不会出错),也是会抛异常的。 “泛型代替不了重载的地方就不该用重载”,这个说绝对,下面这种: add(float a,float b) add(int a,int b,int c) add(char a,char b,char c) 业务毕竟多种多样的,有重载还是利于简化代码的。 方式 1 FancyClassName FancyClassName::FancyClassName(params){ blabla... } instance = new FancyClassName(params) 方式 2 FancyClassName FancyClassName::new(params){ blabla... } instance = new FancyClassName() instance.new(params) 我觉得还是方式 1 更好、更简洁。而且方式 1 规范了 constructor 方式 2 可以是 new 、create 、init 、build....,反而很乱 如果你说可以这样: instance = new FancyClassName.new(params) 那么 new 就是 constructor ,换了名字而已 |
118
hutoer 2021-12-26 17:11:54 +08:00
instance = new FancyClassName.new(params) 这个写错了
instance = FancyClassName.new(params) 这个其实不算 constructor |
119
hutoer 2021-12-26 17:18:26 +08:00
我看错了,把 FancyClassName.new(params) 当实例函数了
|
120
Buges 2021-12-26 17:19:36 +08:00
@hutoer 异常只不过是一种不同的控制流,返回 Color throws ParseError 和返回 Result<Color,ParseError>本质上是一样的,都是返回数据,而这两者返回的数据“类型不同”。
你这个例子是完全可以用泛型的: fn add<A: IAddable<Output=A>>(a:A,b:A,c:A)->A{ } |
121
Buges 2021-12-26 17:24:33 +08:00
@hutoer 上面没打完,constructor 没有提供额外的好处,限制了初始化函数的命名(这也是需要重载的一个主要原因),不能为不同的情况使用不同有意义的命名。至于命名有静态检查,并且一般都有特定的 convention,没什么混乱的。另外不要只从 OOP 的角度观察,简单的函数其实更好理解。
|
122
hutoer 2021-12-26 17:31:00 +08:00
@Buges 抛出异常和返回错误值还是不一样的,调用的地方处理也不一样。就算是返回错误值,可以 Result<Color,Error>,Error 是基类,你这样 Result<Color,ParseError>,有其他类型的错误咋返回?所以 Color::from_rgb(u8,u8,u8)和 Color::from_hex(String)返回类型没有区别。
我那个例子,参数个数不一样的。 |
124
Buges 2021-12-26 18:09:08 +08:00 via Android
@hutoer return 和 throw 是不同的控制流,需要用不同的方式处理,但本质上都是返回数据给调用方,无论通过 return 还是 throw 。实际“返回”的数据类型是不一样的。
如果签名写了 ParseError ,自然是表明该函数只可能返回这一种错误类型,如果还可以返回其他类型那自然要写成所有可能类型的 super type ,这个和 checked exception 本质是一样的。 参数个数不一样可以用 vararg ,或者包装到一个 collection literal 里,或者写成 macro 。如果只需要几种特定数量的参数,可以分别写成 add2 、add3 等不同函数,比起导致的问题重载并不能提供足够的好处。 |
125
agagega 2021-12-26 18:38:55 +08:00 via iPhone
C++因为长期以来没有 optional 类型(而且即使有了也有额外 overhead ),所以构造函数只能用异常表示构造失败。
而不管是 C++风格的构造函数还是手写函数构造,都存在语义不明的问题。Swift 风格的具名参数和重载可以解决,并不一定需要带不同名字的函数。 但即使没有构造函数,这个创建对象的函数也还是需要某种方式来「创建」对象,这种 C 风格花括号的方式有是不如构造函数一样灵活。 另外在面向对象的继承关系里,构造函数就显得很自然,非构造函数虽然也可以做到类似效果,但就会很别扭。 |
126
fregie 2021-12-27 10:05:45 +08:00
@partystart 什么叫好,什么叫不好,这几年开发者们已经用脚投票了,你觉得什么叫好,什么叫不好?
本身都不是面向对象的语言,你非拿它来写业务,写完了还说不好用,那能说你什么?但凡明白点面向对象的也会明白 go 本身就不适合写业务,编程语言没有银弹,不同语言有各自擅长的领域。 |
127
LoNeFong 2021-12-27 12:20:15 +08:00
打起来 打起来 我就喜欢看 V 站语言战争, 一堆人瞎瘠薄操心!
赚几个钱啊? 房贷换完没啊? 真 tm 无聊 |
128
ly020044 2021-12-27 14:46:23 +08:00
我就喜欢看你们打字互喷,下次你们继续哈。
|
129
nmap 2021-12-28 09:57:53 +08:00
别用不就得了嘛,人家也没逼着你用,也没让你掏一分钱
|
130
adoal 2021-12-29 16:36:32 +08:00
你是不是对 PLT 的学术界有什么误解……
go 的错误处理硬生生把本该用 sum type 来做的事( either ok result or error info )做成了 product type ( a tuple with both ok result and error info )……哪个学术界是这么玩的? |