声明一个常量数组

我试过:

const ascii = "abcdefghijklmnopqrstuvwxyz"
const letter_goodness []float32  = { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }
const letter_goodness  = { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }
const letter_goodness = []float32 { .0817,.0149,.0278,.0425,.1270,.0223,.0202, .0609,.0697,.0015,.0077,.0402,.0241,.0675, .0751,.0193,.0009,.0599,.0633,.0906,.0276, .0098,.0236,.0015,.0197,.0007 }

第一个声明和初始化工作正常,但第二个、第三个和第四个就不行。

我如何声明和初始化一个浮动的const数组?

247376 次浏览

数组本质上不是不可变的;你不能让它是常数。

你能得到的最接近的是:

var letter_goodness = [...]float32 {.0817, .0149, .0278, .0425, .1270, .0223, .0202, .0609, .0697, .0015, .0077, .0402, .0241, .0675, .0751, .0193, .0009, .0599, .0633, .0906, .0276, .0098, .0236, .0015, .0197, .0007 }

注意[...]而不是[]:它确保你得到一个(固定大小)数组而不是一个切片。所以值不是固定的,但大小是固定的。

正如@jimt所指出的,[...]T语法是[123]T的糖。它创建一个固定大小的数组,但让编译器计算其中有多少元素。

有效的去:

围棋中的常数就是这个常数。它们是在编译时创建的,即使在函数中定义为局部变量,也只能是数字、字符(符文)、字符串或布尔值。由于编译时的限制,定义它们的表达式必须是常量表达式,可以由编译器求值。例如,1<<3是一个常量表达式,而math.Sin(math.Pi/4)不是,因为对math.Sin的函数调用需要在运行时发生。

切片和数组总是在运行时计算:

var TestSlice = []float32 {.03, .02}
var TestArray = [2]float32 {.03, .02}
var TestArray2 = [...]float32 {.03, .02}

[...]告诉编译器计算数组本身的长度。切片包装数组,在大多数情况下更容易使用。不要使用常量,只需使用小写首字母使变量不能被其他包访问:

var ThisIsPublic = [2]float32 {.03, .02}
var thisIsPrivate = [2]float32 {.03, .02}

thisIsPrivate只在它定义的包中可用。如果你需要从外部读取访问,你可以写一个简单的getter函数(参见golang中的getter)。

在围棋中没有数组常量这样的东西。

引用自Go语言规范:常量:

布尔常量神符常量整型常量浮点型常量复杂的常量字符串常量。符文、整数、浮点数和复杂常数统称为数字常量

常数表达式(用于初始化常量)可能只包含常数操作数,并在编译时计算。

规范列出了不同类型的常量。注意,可以使用常数表达式创建和初始化常量,其中类型的基本类型是允许的类型之一。例如,这是有效的:

func main() {
type Myint int
const i1 Myint = 1
const i2 = Myint(2)
fmt.Printf("%T %v\n", i1, i1)
fmt.Printf("%T %v\n", i2, i2)
}

输出(在去操场上尝试它):

main.Myint 1
main.Myint 2

如果你需要一个数组,它只能是一个变量,而不是一个常数。

我推荐这个关于常量的很棒的博客文章:< >强常量< / >强

正如其他人所提到的,对此没有官方的Go构造。我能想到的最接近的是一个返回切片的函数。通过这种方式,您可以保证没有人会操纵原始切片的元素(因为它是“硬编码”的;进入数组)。

我把你的切片缩短了,使它更短……

func GetLetterGoodness() []float32 {
return []float32 { .0817,.0149,.0278,.0425,.1270,.0223 }
}

除了上面的@Paul的回答,你还可以做下面的如果您只需要访问数组中的单个元素(即,如果你不需要迭代数组,获取它的长度,或从它中创建切片)。

而不是

var myArray [...]string{ /* ... */ }

你可以这样做

func myConstArray(n int) string {
return [...]string{ /* ... */ }[n]
}

然后不再提取元素为

str := myArray[i]

将它们提取为

str := myConstArray(i)

Godbolt上的链接:https://godbolt.org/z/8hz7E45eW(注意在main的汇编中如何不复制数组,以及如果n在编译时已知,编译器如何甚至能够提取相应的元素——这在正常的非const数组中是不可能的)。

如果相反,你需要迭代数组或从数组中创建切片,@Paul的回答仍然是一种方法¹(尽管它可能会对运行时产生重大影响,因为每次调用函数时都需要创建数组的副本)。

不幸的是,这是我们能得到的最接近const数组的东西,直到https://github.com/golang/go/issues/6386被解决。


¹从技术上讲,你也可以像我的回答中描述的那样使用const数组,但它非常丑陋,在运行时肯定不是很有效:https://go.dev/play/p/rQEWQhufGyK