声明一个常量数组

huangapple go评论86阅读模式
英文:

Declare a constant array

问题

我尝试过:

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 }

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

如何声明和初始化一个常量浮点数数组?

英文:

I have tried:

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 }

The first declaration and initialization works fine, but the second, third and fourth don't work.

How can I declare and initialize a const array of floats?

答案1

得分: 363

一个数组本质上是可变的;你不能使它成为常量。

你能做的最接近的是:

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

英文:

An array isn't immutable by nature; you can't make it constant.

The nearest you can get is:

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 }

Note the [...] instead of []: it ensures you get a (fixed size) array instead of a slice. So the values aren't fixed but the size is.

As pointed out by @jimt, the [...]T syntax is sugar for [123]T. It creates a fixed size array, but lets the compiler figure out how many elements are in it.

答案2

得分: 88

Effective Go

> 在Go中,常量就是常量。它们在编译时创建,即使在函数中定义为局部变量,也只能是数字、字符(符文)、字符串或布尔值。由于编译时的限制,定义常量的表达式必须是常量表达式,可以由编译器计算。例如,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函数(参见Getters in golang)。

英文:

From Effective Go:

> Constants in Go are just that—constant. They are created at compile time, even when defined as locals in functions, and can only be numbers, characters (runes), strings or booleans. Because of the compile-time restriction, the expressions that define them must be constant expressions, evaluatable by the compiler. For instance, 1<<3 is a constant expression, while math.Sin(math.Pi/4) is not because the function call to math.Sin needs to happen at run time.

Slices and arrays are always evaluated during runtime:

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

[...] tells the compiler to figure out the length of the array itself. Slices wrap arrays and are easier to work with in most cases. Instead of using constants, just make the variables unaccessible to other packages by using a lower case first letter:

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

thisIsPrivate is available only in the package it is defined. If you need read access from outside, you can write a simple getter function (see Getters in golang).

答案3

得分: 16

在Go语言中,没有数组常量这个概念。

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

英文:

There is no such thing as array constant in Go.

Quoting from the Go Language Specification: Constants:

> There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants. Rune, integer, floating-point, and complex constants are collectively called numeric constants.

A Constant expression (which is used to initialize a constant) may contain only constant operands and are evaluated at compile time.

The specification lists the different types of constants. Note that you can create and initialize constants with constant expressions of types having one of the allowed types as the underlying type. For example this is valid:

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)
}

Output (try it on the Go Playground):

main.Myint 1
main.Myint 2

If you need an array, it can only be a variable, but not a constant.

I recommend this great blog article about constants: Constants

答案4

得分: 11

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

我已经将你的切片缩短了,以使它更短:

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

As others have mentioned, there is no official Go construct for this. The closest I can imagine would be a function that returns a slice. In this way, you can guarantee that no one will manipulate the elements of the original slice (as it is "hard-coded" into the array).

I have shortened your slice to make it...shorter...:

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

答案5

得分: 0

除了@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的汇编中没有对数组进行复制,并且编译器甚至能够在编译时提取相应的元素,这是普通非const数组无法实现的)。

如果你需要迭代数组或创建切片,@Paul的答案仍然是最佳选择(尽管每次调用函数时都需要创建数组的副本,可能会有显著的运行时影响)。

不幸的是,在https://github.com/golang/go/issues/6386问题解决之前,这是我们能够获得的最接近const数组的方法。


¹ 从技术上讲,你也可以按照我的答案中所描述的使用const数组,但这样做非常丑陋,而且在运行时效率肯定不高:https://go.dev/play/p/rQEWQhufGyK

英文:

In addition to @Paul's answer above, you can also do the following if you only need access to individual elements of the array (i.e. if you don't need to iterate on the array, get its length, or create slices out of it).

Instead of

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

you can do

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

and then instead of extracting elements as

str := myArray[i]

you extract them as

str := myConstArray(i)

Link on Godbolt: https://godbolt.org/z/8hz7E45eW (note how in the assembly of main no copy of the array is done, and how the compiler is able to even extract the corresponding element if n is known at compile time - something that is not possible with normal non-const arrays).

If instead, you need to iterate on the array or create slices out of it, @Paul's answer is still the way to go¹ (even though it will likely have a significant runtime impact, as a copy of the array needs to be created every time the function is called).

This is unfortunately the closest thing to const arrays we can get until https://github.com/golang/go/issues/6386 is solved.


¹ Technically speaking you can also do it with the const array as described in my answer, but it's quite ugly and definitely not very efficient at runtime: https://go.dev/play/p/rQEWQhufGyK

huangapple
  • 本文由 发表于 2012年10月30日 18:53:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/13137463.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定