栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Go编译器对常量表达式和其他表达式的评估是否有所不同

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go编译器对常量表达式和其他表达式的评估是否有所不同

在常量和非常量表达式之间的评估存在差异,这是因为常量是精确的:

数字常数表示任意精度的精确值, 并且不会溢出

输入的常量表达式不会溢出;如果结果不能用其类型表示,则为编译时错误(可以在编译时检测到)。

同一件事不适用于非常量表达式,因为在编译时无法检测到(只能在运行时检测到)。对变量的操作可能会溢出。

在第一个示例中,

ONE
是类型为type的类型常量
int
。这个常量表达式:

ONE << (unsafe.Sizeof(x)*8 - 1)

是一个常数移位表达式,适用于:Spec:常数表达式:

如果常量移位表达式的左操作数是未类型化的常量,则结果为整数常量;否则,结果为整数。
否则,它是与左操作数相同类型的常量,该常量必须是
整数类型

因此,shift表达式的结果必须适合,

int
因为这是一个常量表达式。但是由于没有,这是一个编译时错误。

在第二个示例

ONE
中,它不是常量,而是type的变量
int
。因此,此处的移位表达式可能会并且将溢出,从而导致预期的负值。

笔记:

如果您

ONE
在第二个示例中将其更改为常量而不是变量,则会得到相同的错误(因为初始化器中的表达式将是常量表达式)。如果
ONE
在第一个示例中更改为变量,则该变量将不起作用,因为变量不能在常量表达式中使用(它必须是常量表达式,因为它会初始化常量)。

查找最小最大值的常量表达式

您可以使用以下解决方案,得出

uint
int
类型的最大值和最小值:

const (    MaxUint = ^uint(0)    MinUint = 0    MaxInt  = int(MaxUint >> 1)    MinInt  = -MaxInt - 1)func main() {    fmt.Printf("uint: %d..%dn", MinUint, MaxUint)    fmt.Printf("int: %d..%dn", MinInt, MaxInt)}

输出(在Go Playground上尝试):

uint: 0..4294967295int: -2147483648..2147483647

其背后的逻辑在于Spec:常量表达式:

一元按位补数运算符^所使用的掩码与非常数规则匹配:对于无符号常量,掩码均为1,对于有符号和无类型常量,掩码均为-1。

因此,类型化常量表达式

^uint(0)
是类型,
uint
并且是的最大值
uint
:它的所有位都设置为
1
。假设整数使用2的补码表示:将其向左移动,
1
将获得max的值
int
,其中min
int
值为
-MaxInt - 1
-1
由于该
0
值)。

推理不同的行为

为什么常量表达式没有溢出,非常量表达式没有溢出?

后者很简单:在大多数其他(编程)语言中,都有溢出。因此,这种行为与其他语言一致,并且具有其优势。

真正的问题是第一个:为什么常量表达式不允许溢出?

Go中的常量不仅仅是类型化变量的值:它们表示 任意精度的精确值 。如果您要为一个 类型化的 常量分配一个值,那么请保持“ 精确
”一词,允许溢出并分配一个完全不同的值实际上并不能达到 精确

展望未来,这种类型的检查和禁止溢出可能会捕获如下错误:

type Char bytevar c1 Char = 'a' // OKvar c2 Char = '世' // Compile-time error: constant 19990 overflows Char

这里会发生什么?

c1 Char ='a'
之所以有效,
'a'
是因为它是一个
rune
常量,并且
rune
是的别名
int32
,并且
'a'
具有
97
适合
byte
的有效范围(即
0..255
)的数值。

但是会

c2 Char ='世'
导致编译时错误,因为符文的
'世'
数值
19990
不适合
byte
。如果允许溢出,您的代码将编译并分配
22
数值(
'x16'
),
c2
但显然这不是您的意图。通过禁止溢出,可以很容易地在编译时捕获此错误。

要验证结果:

var c1 Char = 'a'fmt.Printf("%d %q %cn", c1, c1, c1)// var c2 Char = '世' // Compile-time error: constant 19990 overflows Charr := '世'var c2 Char = Char(r)fmt.Printf("%d %q %cn", c2, c2, c2)

输出(在Go Playground上尝试):

97 'a' a22 'x16'


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/372114.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号