【问题标题】:Different behavior of len() with const or non-const value具有 const 或非常量值的 len() 的不同行为
【发布时间】:2022-01-06 03:55:57
【问题描述】:

下面的代码

const s = "golang.go"

var a byte = 1 << len(s) / 128

a 的结果是 4。但是,将const s 更改为var s 后如下

var s = "golang.go"

var a byte = 1 << len(s) / 128

a 的结果现在是 0。

还有其他测试代码如下

const s = "golang.go"

var a byte = 1 << len(s) / 128     // the result of a is 4
var b byte = 1 << len(s[:]) / 128  // the result of b is 0

var ss = "golang.go"

var aa byte = 1 << len(ss) / 128    // the result of aa is 0
var bb byte = 1 << len(ss[:]) / 128 // the result of bb is 0

在评估s[:]的长度时,b 为 0 很奇怪

我试着按照golang spec来理解它

如果 s 是字符串常量,则表达式 len(s) 是常量。如果 s 的类型是数组或指向数组的指针并且表达式 s 不包含通道接收或(非常量)函数调用,则表达式 len(s) 和 cap(s) 是常量

但我失败了。有人可以更清楚地向我解释一下吗?

【问题讨论】:

    标签: go constants bit-shift


    【解决方案1】:

    不同之处在于,当s 为常量时,表达式被解释为常量表达式并执行,使用无类型整数类型并产生int 类型。当s 是变量时,表达式被解释为非常量表达式并执行,使用byte 类型。

    Spec: Operators:

    移位表达式中的右操作数必须是整数类型,或者是一个无类型常量representable,其值为uint如果非常量移位表达式的左操作数是无类型常量,则首先将其隐式转换为仅将移位表达式替换为其左操作数时假定的类型。

    s 是一个变量时,引用的部分适用。该表达式是一个非常量移位表达式(1 &lt;&lt; len(s)),因为s 是一个变量(所以len(s) 是非常量),而左操作数是一个无类型常量(1)。所以1 被转换为如果移位表达式被单独替换为它的左操作数,它会假设的类型:

    var a byte = 1 << len(s) / 128
    

    替换为

    var a byte = 1 / 128
    

    在此变量声明中将使用byte 类型,因为该类型用于变量a。所以回到原来的:byte(1)左移9将是0,除以128也将是0

    而当s 为常量时,将使用int,因为Spec: Constant expressions:

    如果常量shift expression的左操作数是无类型常量,则结果是整数常量;否则为与左操作数同类型的常量,必须为整数类型。

    这里1 不会转换为byte1 &lt;&lt; len(s) => 1 &lt;&lt; 9 将是512,除以128 将是4

    【讨论】:

      【解决方案2】:

      Go 中的常量的行为与您预期的不同。它们是“任意精度和_un_typed”。

      对于const consts = "golang.go",表达式1 &lt;&lt; len(consts) / 128 是一个常量表达式,并被评估为具有任意精度的常量表达式,从而产生一个无类型整数4,它可以分配给一个字节,从而产生@ 987654326@.

      对于var vars = "golang.go",表达式1 &lt;&lt; len(vars) / 128 不再是一个常量表达式,而是必须作为一些typed int 来计算。 https://go.dev/ref/spec#Operators中是如何定义的

      移位表达式中的右操作数必须是整数类型或者是可以由 uint 类型的值表示的无类型常量。如果非常量移位表达式的左操作数是无类型常量,则首先将其隐式转换为仅将移位表达式替换为其左操作数时假定的类型。

      第二句话适用于您的问题。 1 被转换为“它将[读取]假定的类型”。拼写为byte(1) &lt;&lt; len(vars),即 0。

      https://go.dev/blog/constants

      【讨论】:

        猜你喜欢
        • 2022-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-20
        • 1970-01-01
        • 2018-10-18
        相关资源
        最近更新 更多