我试过:

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数组?


当前回答

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

你能得到的最接近的是:

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的糖。它创建一个固定大小的数组,但让编译器计算其中有多少元素。

其他回答

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

你能得到的最接近的是:

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的糖。它创建一个固定大小的数组,但让编译器计算其中有多少元素。

来自Effective Go:

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

除了上面@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

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

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

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

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

引用自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)
}

输出(在Go Playground上试试):

main.Myint 1
main.Myint 2

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

我推荐这篇很棒的关于常量的博客文章:constants