在字符串上使用 len 与字符串子切片进行位移时的意外输出

问题描述 投票:0回答:1

我有一个Go程序,它对字符串常量的长度执行位移和除法运算,但输出不是我所期望的。这是代码:

package main

import "fmt"

const s = "123456789" // len(s) == 9

// len(s) is a constant expression,
// whereas len(s[:]) is not.
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128

func main() {
    fmt.Println(a, b) // outputs: 4 0
}

在此程序中,a 和 b 使用涉及移位和除法的类似表达式计算。然而,a 和 b 的输出分别是 4 和 0,这似乎违反直觉,因为这两个操作都涉及相同的字符串长度和相似的算术。有人能解释一下为什么a和b产生不同的结果吗?

  • 在这种情况下除以 128 和位移位有什么作用?
  • 为什么 len(s[:]) 不被视为常量表达式,这对计算有何影响?

如果您能深入了解这些表达式如何以不同的方式求值以及它们为何会在 Go 中产生不同的输出,我将不胜感激。

go bit-shift constant-expression
1个回答
4
投票

差异来自于

len(s)
是常量而
len(s[:])
不是常量,导致第一个转变是常量转变,而第二个转变是非常量转变。

第一个示例是常量移位操作,将在“const”空间中执行,结果将转换为

byte
(因为它适合一个字节)。

第二个例子是非常量移位运算,所以根据规范,

1
会先转换为
byte
,然后将移位和除法作为
byte
值进行(移位结果不适合
byte
,因此结果将是
0
),除以
128
将再次得到
0

来自规范的相关部分:操作员:

移位表达式中的右操作数必须具有 整数类型 (Go 1.13) 或者是可由类型

uint
的值表示的无类型常量。如果非常量移位表达式的左操作数是无类型常量,则它首先会隐式转换为移位表达式仅由其左操作数替换时所假定的类型。

参见相关:Golang 移位运算符转换

至于为什么

len(s[:])
不是常量,请参见规范:切片表达式:

除了无类型字符串之外,如果切片操作数是字符串或切片,则切片操作的结果是与操作数类型相同的非常量值。 对于无类型字符串操作数,结果是

string
类型的非常量值。

您可能会争论索引值是否也是常量,切片常量字符串可能会产生常量值,但这种专业化当前不可用,并且由于它会改变当前程序的结果(例如在您的问题中),因此它以后可能也不会制作了。

© www.soinside.com 2019 - 2024. All rights reserved.