https://mp.weixin.qq.com/s/L6ysPUCyYhAwL6PsKXykhQ
你为什么使用常量?
why_might_you_use_constants
你不想在代码中到处定义魔法数值[1],于是使用常量来声明它们,并在代码中再次使用它们。
魔法数值是不安全的,你需要准确声明它们,因此,常量是一个安全的选择。除此之外,在代码中看到常量而不是魔法数值也是令人高兴的;人们可以更好地理解代码是怎样的。
我们希望我们可以在使用常量中获得运行速度上的收益,因为,使用常量能够使编译器能够进行更多的优化,它将知道常量的值永远不会改变。
我最喜欢的是非类型化常量。它真是个天才的想法。当使用非类型化常量时,你将获得更多的灵活性和高精度的计算。
类型常量
typed_constants.image
类型 →Boolean,rune,numerics,或者 string
值 → 编译期时在声明中分配值
地址 → 你无法得到它在内存中的地址(不像变量)
你无法在声明常量之后再改变它
你不能使用运行时的结构,例如变量,指针,数组,切片,map,结构体,接口,方法调用,或者方法的值。
类型化常量声明
image
图中定义了一个类型常量 Pi,它的类型为 float64,值为 3.14
运行并且尝试代码示例,请点击这里[2]
声明多个常量
image
运行图中的代码并且检验它的结果,请点击这里[3]
在一个代码块中声明多个具有不同类型不同值的常量
当一个常量的类型和值没有声明时,它将从上一个常量中得到它。在上面,pi2 从 pi 中获取其类型和值。
Age 常量在声明时有一个新的值。并且,它通过赋值为 10 获取默认的类型 int。
可以在同一行和多个变量[4]声明中定义多个常量。
非类型化常量
它们有很好的特性,比如高精度的计算以及在所有数值表达式中使用它们而不声明类型等。下面我将介绍这些特性。它们就像 Go 中的通配符。
iamge
理想类型 → 与 Go 通常类型不同的隐藏类型。
理想值 → 存在于理想值空间中,并且具有默认类型。
默认类型 → 取决于理想值。
非类型化常量的声明
image
声明了一个非类型化的常量 Pi,并且为它赋值为 3.14,那么它默认的类型就是 float。
image
当需要它的类型的时候,图片左侧(期望类型)将转化为右边的类型(预先声明的类型)
尝试代码,点击这里[5]
高精度计算
如果常量只停留在非类型化常量领域,那么它没有速度的限制!但是,当将常量赋值给变量进行使用时,速度就有限制了。
image
当你将其分配给变量时,非类型化常量的精度会降低,其默认类型会转换为 Go 的普通类型[6]。
运行代码示例,请点击这里[7]
灵活的表达方式
你可以使用非类型化常量临时从 Go 的强类型系统中逸出,直到它们在类型要求表达式中的计算为止。
我在代码中[8]一直使用它们时,会避免在不需要强类型时声明它们。所以,如果你不真正需要常量,就不要用它声明类型。
运行代码示例
Understand when and how to use untyped constants[9]
We can assign an untyped constant to any numeric-type variable[10]
常量作用范围
image
一个常量只能在它的声明的作用域内使用。如果你在更内部的作用域内以同样的名字再声明一个常量,那么这个常量仅仅在内部作用域内可以使用,并且在此作用域内将覆盖外部声明的常量。查看代码示例,请点击这里[11]
via: https://blog.learngoprogramming.com/learn-golang-typed-untyped-constants-70b4df443b61
作者:Inanc Gumus[12]译者:xmge[13]校对:polaris1119[14]
本文由 GCTT[15] 原创编译,Go 中文网[16] 荣誉推出
参考资料
[1]
魔法数值: https://en.wikipedia.org/wiki/Magic_number_%28programming%29
[2]
请点击这里: https://play.golang.org/p/mrnqxa8Kic
[3]
请点击这里: https://play.golang.org/p/mBoqG58z_e
[4]
多个变量: https://blog.learngoprogramming.com/learn-go-lang-variables-visual-tutorial-and-ebook-9a061d29babe#4176
[5]
这里: https://play.golang.org/p/L5UC3XgYFk
[6]
普通类型: https://golang.org/ref/spec#Boolean_types
[7]
请点击这里: https://play.golang.org/p/4ODv0n_stw
[8]
代码中: https://github.com/inancgumus/myhttp/blob/master/get.go#L12
[9]
Understand when and how to use untyped constants: https://play.golang.org/p/2cgFoB4rYD
[10]
We can assign an untyped constant to any numeric-type variable: https://play.golang.org/p/7-VMh5egC-
[11]
请点击这里: https://play.golang.org/p/c3-GF_a5iI
[12]
Inanc Gumus: https://www.activestate.com/blog/author/peteg/
[13]
xmge: https://github.com/xmge
[14]
polaris1119: https://github.com/polaris1119
[15]
GCTT: https://github.com/studygolang/GCTT
[16]
Go 中文网: https://studygolang.com/
When declaring two const variables (one typed and one untyped), and printing out the type of the second one, like:
const x float32 = 10000
const y = 1e8 / x
fmt.Printf(“the type of y: %T
“, y)
// or with reflect:
fmt.Println(reflect.TypeOf(y))
it tells me, that
y
is of type
float32
.
Well this doesn’t come as a surprise, since the the untyped const variable
y
is defined as dividing an untyped float constant by a typed float constant and therefore the type might be inferred.
According to “Go by Example” (https://gobyexample.com/constants), constants never have a type, unless explicitly provided. However, according to the official Go blog documentation, untyped constants do have hidden types that get inferred, but let the constant remain untyped until a type is needed.
I would have assumed, that
y
would still be an untyped float constant. However, when using it for assigning a new variable, Goland’s inspector tells me, that the type can be omitted:
const z float32 = y
// ^^^ type can be ommitted
So finally, my question would be:
Is it impossible to declare an untyped constant out of typed constant expressions?
在声明两个const变量(一个为类型,一个为非类型)并打印第二个const类型时,例如 :</ p>
const x float32 = 10000
const y = 1e8 / x
fmt.Printf(“ y的类型:%T
”,y)
//或带有反射:
fmt.Println(reflect.TypeOf(y))
</ code> </ pre>
它告诉我, y </ code>是 输入 float32 </ code>。 </ p>
这并不奇怪,因为无类型的const变量 y </ code>被定义为将无类型的浮点常量除以有类型的浮点常量,因此
根据“按示例执行”( https://gobyexample.com/constants < / a>),除非明确提供,否则常量永远不会具有类型。 但是,根据Go官方博客文档,未类型化的常量 do </ strong>具有可以推断出的隐藏类型,但是让该常量保持未类型化,直到需要一个类型为止。 </ p>
我会假设, y </ code>仍然是无类型的浮点常量。 但是,在使用它分配新变量时,Goland的检查员告诉我,可以省略该类型:</ p>
const z float32 = y
// ^^^ type 可以省略
</ code> </ pre>
所以最后,我的问题是:
是否无法从类型化常量表达式中声明未类型化常量?</ p>
</ div>
A const declaration gives names to constants, that is, values that are fixed at compile time. The value of a constant must be a number, string, or boolean.
const的值只能是数字,字符串或者布尔值。
A constant declaration may specify a type as well as a value, but in the absence of an explicit type, the type is inferred from the expression on the right-hand side.
当定义常量时没有指定其类型时,常量的类型将由等号右边的表达式来决定。
下面是如何定义一组constant:
When a sequence of constants is declared as a group, the right-hand side expression may be omitted for all but the first of the group, implying that the previous expression and its type should be used again. For example:
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // “1 1 2 2”
A const declaration may use the constant generator iota, which is used to create a sequence of related values without spelling out each one explicitly. In a const declaration, the value of iota begins at zero and increments by one for each item in the sequence. For example:
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
) This declares Sunday to be 0, Monday to be 1, and so on.
另外,关于untyped constants的定义:
Constants in Go are a bit unusual. Although a constant can have any of the basic data types like int or float64, including named basic types like time.Duration, many constants are not committed to a particular type. The compiler represents these uncommitted constants with much greater numeric precision than values of basic types, and arithmetic on them is more precise than machine arithmetic; you may assume at least 256 bits of precision. There are six flavors of these uncommitted constants, called untyped boolean, untyped integer, untyped rune, untyped floating-point, untyped complex, and untyped string.
只有constant才可能是untyped,变量不可能是untyped。
Only constants can be untyped. When an untyped constant is assigned to a variable, as in the first statement below, or appears on the right-hand side of a variable declaration with an explicit type, as in the other three statements, the constant is implicitly converted to the type of that variable if possible.
var f float64 = 3 + 0i // untyped complex -> float64
f = 2 // untyped integer -> float64
f = 1e123 // untyped floating-point -> float64
f = ‘a’ // untyped rune -> float64
The statements above are thus equivalent to these:
var f float64 = float64(3 + 0i)
f = float64(2)
f = float64(1e123)
f = float64(‘a’)
constant之间转化要考虑是否有可能溢出:
Whether implicit or explicit, converting a constant from one type to another requires that the target type can represent the original value. Rounding is allowed for real and complex floating-point numbers:
const (
deadbeef = 0xdeadbeef // untyped int with value 3735928559
a = uint32(deadbeef) // uint32 with value 3735928559
b = float32(deadbeef) // float32 with value 3735928576 (rounded up)
c = float64(deadbeef) // float64 with value 3735928559 (exact)
d = int32(deadbeef) // compile error: constant overflows int32
e = float64(1e309) // compile error: constant overflows float64
f = uint(-1) // compile error: constant underflows uint )
要注意把untyped constant赋值给变量时,变量类型的选择。
In a variable declaration without an explicit type (including short variable declarations), the flavor of the untyped constant implicitly determines the default type of the variable, as in these examples:
i := 0 // untyped integer; implicit int(0)
r := ‘\000’ // untyped rune; implicit rune(‘\000’)
f := 0.0 // untyped floating-point; implicit float64(0.0)
c := 0i // untyped complex; implicit complex128(0i)
Note the asymmetry: untyped integers are converted to int, whose size is not guaranteed, but untyped floating-point and complex numbers are converted to the explicitly sized types float64 and complex128. The language has no unsized float and complex types analogous to unsized int, because it is very difficult to write correct numerical algorithms without knowing the size of one’s floating-point data types.
To give the variable a different type, we must explicitly convert the untyped constant to the desired type or state the desired type in the variable declaration, as in these examples:
var i = int8(0)
var i int8 = 0
These defaults are particularly important when converting an untyped constant to an interface value since they determine its dynamic type.
fmt.Printf(“%T\n”, 0) // “int”
fmt.Printf(“%T\n”, 0.0) // “float64”
fmt.Printf(“%T\n”, 0i) // “complex128”
fmt.Printf(“%T\n”, ‘\000’) // “int32” (rune)