V 站的朋友们,想问一个关于 Go 的“基本类型零值问题”的问题?

2023-09-09 21:09:56 +08:00
 yaodao

V2EX 的朋友们大家好。

目前我正在学习 GO 语言,是个入门小白,试着从应用的角度去学习 GO 语言,想先从 web 开发入手去做一些有意思的后台应用。

于是我挑选了 Fiber 作为 web 框架,XORM 作为数据库(目前只涉及 mysql )的交互框架。

当我试着基于数据库去做一些查询功能时,我懵逼了。

我需要根据一个结构体参数( Java 中叫参数对象)中是否有某个字段来决定我的 sql 中的 where 条件中是否要有这个筛选条件。

例如下面这段代码片段:

type Param struct {
	UserId    int64
	Type      int
	StartTime time.Time
	EndTime   time.Time
}
session := engine.Where("is_delete = 0")
// userId 不为空时
if param.UserId != 0 {
	session.And("user_id = ?", param.UserId)
}

我一开始尝试着写 param.UserId != nil 幸好有编译器告诉我这是错误的写法,我只能摈弃继承于 Java 的编程思想。可是现在问题来了,我如何区分,到底这个 0 是来自默认赋值,还是用户真的输入了一个 0 呢?

或者说有什么优雅的方法能解决我的这种场景么?还是说 golang 真的存在某些局限性不适合做 web 开发?

先提前感谢大佬们和前辈们的指教!

参考链接: go 的零值问题: https://youwu.today/skill/backend/golang-zero-value-and-reference-and-null-value-testing/#%E5%AD%97%E7%AC%A6%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E7%A9%BA%E5%80%BC%E5%88%A4%E6%96%AD

XORM 的使用: https://xorm.io/docs/chapter-05/1.conditions/

2261 次点击
所在节点    Go 编程语言
30 条回复
lysS
2023-09-10 11:58:15 +08:00
这和语言没关系啊
ninjashixuan
2023-09-10 15:13:40 +08:00
@lanlanye 是的,不想用指针就在业务层面规避,日常使用枚举就是 iota+1 。
peterlitszo
2023-09-10 15:39:15 +08:00
@leonshaw 的确,不过作为一个相对较新的语言,的确还是令人大吃一惊......
peterlitszo
2023-09-10 15:46:02 +08:00
@cosiner 只能说这是作者的选择,其他一些语言是明确区分空和非空的,比如 TypeScript ,我们使用 int | undefined (我们有语法糖,也就是符号 ? 来帮助我们定义这种类型),比如 Rust ,我们有 Option<T> 来帮助我们定义。我认为 Rust 或者 Haskell 这种方案的确是最好的,它要求使用者先解包再使用,不用担心 NPE ,而且也不用担心心智负担。我个人认为最糟糕的就是 context.Context ,很多业务场景就把一些乱七八糟的东西往里面塞,你根本不知道里面到底有没有你想要的东西,这种方式太糟糕了。
debuggerx
2023-09-10 17:18:52 +08:00
这是硬伤,已经碰到好多次相关的问题了。
我的选择是宁愿选 sql.nullXxx 系列,虽然难看繁琐但好歹路子是对的;用指针只能说是逆行倒施,而用默认值只能说是错的离谱。
cosiner
2023-09-10 17:50:49 +08:00
@peterlitszo 任何语言 int 的定义都只能表示一个 32/64bit 值, Integer, int|undefined, Optional<T>, ?这种都是有附加属性的, 和 int 完全不对等, 类型都不一样, 不然 optional 的 true 和 false 是在哪里存储的.
go 现在也有范型可以定义 Optional[T], 只能说语言层面没有语法糖, 写起来不方便

至于 context 我基本只用它的 Done() channel, value 之类的只能约定项目规范了, 我不是很了解
Sendya
2023-09-11 11:15:33 +08:00
我们这的类型定义从 1 开始,不用 0 值。
dyllen
2023-09-13 11:41:05 +08:00
@peterlitszo 业务数据往里面塞那不就是用错了 context ,context 本意是用来做协程控制的,虽然可以带数据,那也是带一些通用固定的数据。
peterlitszo
2023-09-13 12:55:49 +08:00
@dyllen 的确说得很好听,但是就是架不住大家滥用。traceid 放进去了,权限校验放进去了,logger 放进去了,我都不知道还有啥没有放进去过。这个 context 老老实实做个协程控制的不好吗?偏偏搞一个伪 map ,一点都不强类型。
peterlitszo
2023-09-13 13:00:07 +08:00
@cosiner 就要要让它类型不一样啊..... Option<T> 这个就是附加一个小 tag ,后面跟个 union 。

至于 Option 设计和 Result 设计,很多地方都要看相关的设计哲学的。如果你标准库都 “凑合凑合”,那很多第三方库也 “凑合凑合”,然后你写的代码也开始 “凑合凑合” 了。

“什么?区分无值、零值、其他值?区分这么多干什么?会不会写工程?工程讲究的就是实现快!”

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/972343

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX