[golang 语言] 为啥在 golang 中不支持将 bool 强转成 int?
引言
今天写代码,发现bool不能直接强转成int,这就导致如下代码编译错误
type Status int
const StatusSuccess Status = 1
...
status := StatusSuccess
succ += int(status == StatusSuccess)
这种在其他语言,例如 c++看起来非常自然的强转为啥 golang 不支持呢?
第二个问题
于是开始 Google,搜到这篇博客,作者用了 7 中方法实现 bool 转 int ,这里摘抄几个。
方法 1
func boolToInt(b bool) int {
if b {
return 1
}
return 0
}
方法 2
func Bool2int(b bool) int {
// The compiler currently only optimizes this form.
// See issue 6011.
var i int
if b {
i = 1
} else {
i = 0
}
return i
}
方法 7
func fastBoolConv(b bool) int {
return int((byte)(unsafe.Pointer(&b)))
}
性能对比
way 1 6449ms
way 2 2868ms
way 3 6378ms
way 6 7268ms
way 7 2987ms
尝试去看方法 2 为啥比方法 1 快,但是没有看懂,有大佬能解释下吗,issue 6011
0x0f.me/blog/golang-compiler-optimization/
这篇文章不是解释了吗?
编译器优化了
我测了一下,go 1.23 方法 1 跟 2 好像都优化了
#2 1 没有 godbolt.org/z/ef93PTPaj
我又看了一下,确实,刚才我用 VScode 看汇编显示不出来,现在显示出来了,方法 1 多了一个跳转
不过,测基准,差不多
统统 cast 库转换
先说行不行
int 和 bool ,在内存布局上就是完全不一样的,通常来说 bool 算上 padding 也不会有一个 int 那么大。
那何来“强转”一说?
再说是不是
go 的出现,就是 google 的工程师为了解决 c/c++的某些问题。包括但不限于:隐式类型转换,void*,滥用模板元编程,晦涩的 memory model 等等。但是你想做的事情又把问题带了回来。
只是因为标准没写吧,c 倒是有 "A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.",不过 reinterpret_cast
最简单和优化的写法还是得看 github.com/golang/go/issues/6011
看来不能用 return 1 和 0 的方式,这样不优化,需要把 1 和 0 赋值给变量再返回才行
更具体的 en.cppreference.com/w/cpp/language/implicit_conversion#Integral_conversions ,也说了,这不是 cast/conversion ,而是 integer promotion
我翻了下 Go 的 Github Issue ,其实有非常多人的提过这个 int(bool) proposal 。
包括今年也有关于这个的讨论: github.com/golang/go/issues/6011
看得出来不少 Go 团队的成员是支持加入这个特性的,主要反对的人是 rsc ,他认为这个变更工作量很大,同时觉得收益不高,Go 团队时间有限,要搞的话你们自己搞:1. spec 的变更; 2. 编译器和 go/types 的变更; 3. 把 Go 主仓库相关代码更新了以尽可能用上这个新特性,来证明这个特性对于 Go 而言是有用的。
所以感觉更接近 Go 早期版本忽视了这个特性,然后现在随着 Go 发展要加进这个特性工作量大了就懒得搞了。
老兄,帮忙再看一下,之前测基准没啥区别,感觉是不是直接内联优化了 godbolt.org/z/fh7WqMvhx
千万别加入这种沙雕转换。
写 C++的时候偶尔手误就会写成
if( a=b) // or (a =1 )
{
// do
}
检查一小时才能在一个角落里看到错误
现在的编译器都会对这种错误警告的,当然,如果不关注警告另说。
这么喜欢骚操作 还是回去 C 吧
有没有可能,c/c++的 bool 就是 0 跟 1 ?不过是加了个 typedef ?你用 while(1){}也能实现 bool true 的功能。不要把你 JavaScript 的坏习惯带到 go 里面,更不要强行扯到 c/c++上。
#13 很多人写代码压根不看 IDE 的警告,一打开文件右侧全是飘黄警告
确实是这样, 我让团队的同学都在 ide 里配置一下 golangci-lint 这个东西, 很多人不配置,还有的配置了不用,不看, 导致很多基础的,有问题的代码都提交上来了, 我发现了再去找他们, 现在 ide 和一些工具挺智能的, 很多常见的坑都能发现
项目大起来,几十个 warning 那不都很正常,只要不飘红,很少关注 warning ,无意中多一个 warning 也很难注意到
JavaScript 欢迎你,隐式转换多到飞起,爽歪歪
好贴
这编译器优化能力也太逆天了。。。难怪那么多人黑
lz 说的是强转,你这是隐式类型转换
因为你先入为主
我搞这么多年,没印象在那里需要用到这种特性。
能转才不正常吧? C/C++那种对 bool 进行++或者其他计算的操作逻辑意义是啥? bool 就是 bool ,真或假,凭什么假的加 1 就变真了? 0 凭什么就是假的?那我负数为啥又是真了?类型该是啥就是啥,别瞎用。以前写 C++的时候碰到有人给 bool 做数值运算我一定要喷到他以后再也不敢。逻辑就是逻辑,数值就是数值,混用你不出错就怪了。
没必要
语义也变得不明确了,得不偿失
防御性编程必备操作,怎么到 Go 这里就行不通了。
内存布局不一样咋就不能强转了,go 不是照样允许 int32 转 float64 么。
而且就一个 bool 到 int 的强转而已,和你下面说的东西都没啥关系,某些连 i32 -> i64 的隐式转换都不允许的语言照样也允许 bool 强转 i32 。
c++的 bool 实际细节大小和 int 不一样,而且 int 可以直接赋值给 bool
我不到啊 建议写 if cond {1} else {0}, 感觉还不如 cast
大哥,我求你们别搞这些花里胡哨的写法了好吗? 还嫌 c++不够脑残是吧
发现自己贴错了 issue: github.com/golang/go/issues/64825 ( x
这个讨论还提到一个点,就是常量,现在常量由于这个类型转换的限制可能对于同个常量会写两个类型( bool/int ),这在 Go 编译器和运行时的代码里就有出现( src/internal/goexperiment/exp_arenas_on.go ):
const Arenas = true
const ArenasInt = 1
总之这事目前来看没有明确拒绝的理由,更接近于懒得搞,如果有人愿意费力气把这变更做了,感觉 Go 团队这边也会接受。
(其实这种类似的情况在 Go 社区有很多,习惯就好)
语言是否允许 cast bool → Integer 和 op 的用例不合理是两回事
写 if succ then sc += 1 很好
Ver. 1 和 Ver. 2 有差异只能说编译器乐色
if(1 == a)这样写可以避免
Benchmark 测试没区别呀
坏了,我搜了一下,linux 内核中少说也有几百处 bool 参与数值运算代码
移位的: github.com/torvalds/linux/blob/master/sound/soc/codecs/wsa881x.c#L912
按位或: github.com/torvalds/linux/blob/master/arch/arm/mach-omap2/display.c#L310
相加的: github.com/torvalds/linux/blob/master/arch/arm64/kvm/arm.c#L308
相减的: github.com/torvalds/linux/blob/master/arch/arm64/kvm/vgic/vgic.c#L262 (这里虽然用到了强制类型转换,但在某些人看来应该同样罪大恶极)
相乘的: github.com/torvalds/linux/blob/master/net/sctp/sm_make_chunk.c#L3689
…… 太多了,更本数不清
本来就是个正常的需求,说有取舍也就算了,非要把它批倒批臭。
泛型的事情过去才几年啊,忘啦?那个 proposal 还挂在 issues 上,天天地盯着你们啊!
建议用 if (status == StatusSuccess) succ += 1 形式,语义上更清晰。
go 编委会喜欢打脸,前期各种不方便之处被各种网红文举说成优点和取舍,泛型就是其中之一
那你直接用 c++不就行了,用锤子 go
酷壳似乎好长时间没有像《编程真难啊》或是《老手是这样教新手编程的》或是像《如何写出无法维护的代码》这样“严肃正经”的文章了,所以,赶在大家还没有向我扔臭鸡蛋前奉献一篇。这篇文章…
时间线: 上周末:在 CF 上购买了域名并部署了一个工具页面来跑流程练练手,这时候购买完毕已经收到收据了; 这周二:CF 发邮件过来说我的账号需要进行付款欺诈的安全检查,需要…
这个图片太经典了,本来想翻译的,后来觉得这么经典的图片可能早已被人翻译了,简单的Google一下,果然有人翻译了。那我就把英文版和中文版都转过来吧。我们可以看到,其中很大一部分…