『InfoQ』Go 语言的微吐槽,这是一篇实践者对( 四 )


日期格式API
Go的日期格式实在让人摸不着头脑 。 Go没有使用常用的strftime%Y-%m-%d格式或yyyy-mm-dd格式 , 而是使用了占位符数字和具有特殊含义的单词 。 如果要在Go中使用yyyy-mm-dd格式设置日期 , 则必须使用“2006-01-02”格式的字符串 。 2006是年份的占位符 , 01是月份的占位符 , 而02是日期的占位符 。 Jan一词代表月份 , 各个月份以三个字母的缩写表示 , 如Jan、Feb、Mar……以此类推 。
我觉得这毫无必要 。 不查看文档是很难记住它的 , 实在太乱了 , 并且没有充分理由就抛弃了已经有半个世纪历史的strftime标准格式 。
我还发现time包的官方文档在解释这部分内容时一团糟 。 它基本没讲明白工作机制 , 结果是你必须去找那些以清晰易懂的方式解释清楚这个问题的第三方资源才行 。
非类型化的常量看下这段代码:
sess,err:=mongo.Connect("mongodb://...")iferr!=nil{returnerr}
defermongo.Disconnect(sess)
【『InfoQ』Go 语言的微吐槽,这是一篇实践者对】ctx,cancel:=context.WithTimeout(context.Background(),15)defercancel()
iferr:=sess.Ping(ctx,nil){returnerr}
看起来人畜无害 。 我们连接到MongoDB数据库 , 在函数退出时defer断开连接 , 然后创建一个具有15秒超时的上下文 , 并使用此上下文运行一个ping命令 , 对数据库运行状况检查 。 这应该能顺利运行 , 但可惜不行 , 每次运行都会返回一个contextdeadlineexceeded错误 。
因为我们创建的上下文没有15秒的超时 , 它的超时时间是15纳秒 。 这叫超时吗?这是瞬间失败 。
context.WithTimeout函数接受一个context.Context和一个time.Duration 。 time.Duration是一个新类型 , 定义为typeDurationint64 。 由于Go的非类型化常量的缘故 , 我们能够将一个int传递给这个函数 。 也就是说 , 在常量被赋予类型之前是没有类型的 。 因此 , 15不是一个整数字面量或整数常数 。 当我们将其作为time.Duration传递时 , 它将被类型化为time.Duration 。
所有这一切意味着 , 没有类型错误或lint告诉我们 , 我们没有给这个函数一个适当的time.Duration 。 正常来说你要把这个函数time.Second*x传递给timeout , 单位是x秒 。 time.Second的类型是time.Duration , 它与x相乘后会进行类型化 , 让这里的类型保持安全 。 但现在并不是这回事 , 一个没有类型的常量与真实的time.Duration一样有效 , 于是就搞出来上面那摊子麻烦 。
总结
Go是一种有趣且非常有用的语言 。 简洁是它的宗旨 , 而且它在大部分时候都做到了这一点 。 但是 , 简单性不应该高于正确性 。 如果你选择简单性而不是正确性 , 那么到头来你会偷工减料 , 并交付有问题的解决方案 。
我认为Go模块与Gitlab的交互就是一个很好的例子 。 Go决定采用一种“简单”的解决方案 , 不像其他那些语言那样做一个包存储中心 , 而是从git服务器中获取内容 。 结果不仅在对git服务器进行身份验证时会出现严重错误 。 当git服务器的命名/分组约定与GitHub不同时 , 它也会出错 。 最后 , 你浪费了一整天的时间来研究stackoverflow , 试图解决这个“简单”的软件包系统的问题 。
我一直在关注Go2的提案 , 并且很高兴看到Go团队在这方面投入了很大努力 。 他们正在收集很多社区反馈 , 这是很好的做法 。 用户经常会提供非常有趣的反馈 。 Go2是修复本文中提到的某些问题的绝好机会 , 或者至少可以允许用户创建自己的数据结构和类型集 , 从而解决其中的一些问题 。
我可以断定 , 当Go2到来时 , 我将编写大量实用程序和数据结构来让程序更安全 , 更加人性化 。
参考阅读:
https://blog.sbstp.ca/go-quirks/