文章目录
- Operators【运算符】
- Operator precedence
- Arithmetic operators
- Integer operators
- Integer overflow
- Floating-point operators
- String concatenation
- Comparison operators
- Logical operators
- Address operators
- Receive operator
- Conversions
- Conversions between numeric types
- Conversions to and from a string type
- Conversions from slice to array or array pointer
- Constant expressions
- Order of evaluation
Operators【运算符】
Operators combine operands into expressions.
Expression = UnaryExpr | Expression binary_op Expression .
UnaryExpr = PrimaryExpr | unary_op UnaryExpr .binary_op = "||" | "&&" | rel_op | add_op | mul_op .
rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
add_op = "+" | "-" | "|" | "^" .
mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
Comparisons are discussed elsewhere. For other binary operators【二元运算符】, the operand types must be identical unless the operation involves shifts or untyped constants. For operations involving constants only, see the section on constant expressions.
Except for shift operations【移位运算符】, if one operand is an untyped constant and the other operand is not, the constant is implicitly converted to the type of the other operand.
The right operand in a shift expression must have integer type [Go 1.13] or be an untyped constant representable by a value of type uint
. If the left operand of a non-constant shift expression is an untyped constant, it is first implicitly converted to the type it would assume if the shift expression were replaced by its left operand alone.【左边的操作数首先会被隐式转换为如果该位移表达式被替换为仅有左边的操作数时的类型】
注意:int和uint在32系统上是32位,在64位系统上是64位!
var a [1024]byte
var s uint = 33// The results of the following examples are given for 64-bit ints.
var i = 1<<s // 1 has type int。var i = 1,1的类型是int
var j int32 = 1<<s // 1 has type int32; j == 0。var j int32 = 1,1的类型是int32
var k = uint64(1<<s) // 1 has type uint64; k == 1<<33。var k = uint64(1),1的类型是uint64
var m int = 1.0<<s // 1.0 has type int; m == 1<<33
var n = 1.0<<s == j // 1.0 has type int32; n == true
var o = 1<<s == 2<<s // 1 and 2 have type int; o == false
var p = 1<<s == 1<<33 // 1 has type int; p == truevar u = 1.0<<s // illegal: 1.0 has type float64, cannot shift
var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift
var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift
var v1 float32 = 1<<s // illegal: 1 has type float32, cannot shift
var v2 = string(1<<s) // illegal: 1 is converted to a string, cannot shift
var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression; w == 1<<33
var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds
var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33// The results of the following examples are given for 32-bit ints,
// which means the shifts will overflow.
var mm int = 1.0<<s // 1.0 has type int; mm == 0
var oo = 1<<s == 2<<s // 1 and 2 have type int; oo == true
var pp = 1<<s == 1<<33 // illegal: 1 has type int, but 1<<33 overflows int
var xx = a[1.0<<s] // 1.0 has type int; xx == a[0]
var bb = make([]byte, 1.0<<s) // 1.0 has type int; len(bb) == 0
Operator precedence
Unary operators【一元运算符】 have the highest precedence.
As the ++
and --
operators form statements, not expressions, they fall outside the operator hierarchy【++和–运算符加上操作数组合成语句,所以不在运算符层级中】. As a consequence, statement *p++
is the same as (*p)++
.
There are five precedence levels for binary operators. Multiplication operators bind strongest, followed by addition operators, comparison operators, &&
(logical AND), and finally ||
(logical OR):
Precedence Operator5 * / % << >> & &^4 + - | ^3 == != < <= > >=2 &&1 ||
Binary operators of the same precedence associate from left to right. For instance, x / y * z
is the same as (x / y) * z
.
+x // x
42 + a - b // (42 + a) - b
23 + 3*x[i] // 23 + (3 * x[i])
x <= f() // x <= f()
^a >> b // (^a) >> b
f() || g() // f() || g()
x == y+1 && <-chanInt > 0 // (x == (y+1)) && ((<-chanInt) > 0)
Arithmetic operators
Arithmetic operators apply to numeric values and yield a result of the same type as the first operand. The four standard arithmetic operators (+
, -
, *
, /
) apply to integer, floating-point, and complex types; +
also applies to strings. The bitwise logical and shift operators【位逻辑运算符和移位运算符】 apply to integers only.
+ sum integers, floats, complex values, strings
- difference integers, floats, complex values
* product integers, floats, complex values
/ quotient integers, floats, complex values
% remainder integers& bitwise AND integers
| bitwise OR integers
^ bitwise XOR integers
&^ bit clear (AND NOT) integers<< left shift integer << integer >= 0
>> right shift integer >> integer >= 0
If the operand type is a type parameter, the operator must apply to each type in that type set. The operands are represented as values of the type argument that the type parameter is instantiated with, and the operation is computed with the precision of that type argument. For example, given the function:
func dotProduct[F ~float32|~float64](v1, v2 []F) F {var s Ffor i, x := range v1 {y := v2[i]s += x * y}return s
}
the product x * y
and the addition s += x * y
are computed with float32
or float64
precision, respectively, depending on the type argument for F
.
Integer operators
For two integer values x
and y
, the integer quotient【商】 q = x / y
and remainder【余数】 r = x % y
satisfy the following relationships:
x = q*y + r and |r| < |y|
with x / y
truncated towards zero (“truncated division”).
x y x / y x % y5 3 1 2
-5 3 -1 -25 -3 -1 2
-5 -3 1 -2
The one exception to this rule is that if the dividend【被除数】 x
is the most negative value for the int type of x
, the quotient q = x / -1
is equal to x
(and r = 0
) due to two’s-complement integer overflow:
x, q
int8 -128
int16 -32768
int32 -2147483648
int64 -9223372036854775808
int
类型的最小负值是什么?
- 在二进制补码表示中,
int
的最小值是-2^(n-1)
,其中n
是位数。- 例如
int32
的最小值是-2147483648
(即-2^31
)。 int64
的最小值是-9223372036854775808
(即-2^63
)。
- 例如
- 为什么
x / -1
会等于x
?
- 数学上,
x / -1
应该等于-x
。 - 但当
x
是最小负值时,-x
会超出int
的正数范围:- 例如
int32
的-(-2147483648)
应该是2147483648
,但int32
的最大值是2147483647
,无法表示。
- 例如
- 由于二进制补码的溢出规则,Go 选择直接返回
x
,而不是报错或未定义行为。
- 余数为什么是 0?
- 根据整数除法的定义:
x = q * y + r
,其中|r| < |y|
。 - 这里
q = x
,y = -1
,所以r = x - (x * -1) = x + x = 2x
,但实际余数为 0。 - 这是语言规范的特殊规定,目的是保持一致性。
If the divisor【除数】 is a constant, it must not be zero. If the divisor is zero at run time, a run-time panic occurs. If the dividend is non-negative and the divisor is a constant power of 2, the division may be replaced by a right shift, and computing the remainder may be replaced by a bitwise AND operation:
x x / 4 x % 4 x >> 2 x & 311 2 3 2 3
-11 -2 -3 -3 1
The shift operators shift the left operand by the shift count specified by the right operand, which must be non-negative. If the shift count is negative at run time, a run-time panic occurs. The shift operators implement arithmetic shifts if the left operand is a signed integer and logical shifts if it is an unsigned integer. There is no upper limit on the shift count. Shifts behave as if the left operand is shifted n
times by 1 for a shift count of n
. As a result, x << 1
is the same as x*2
and x >> 1
is the same as x/2
but truncated towards negative infinity.
For integer operands, the unary operators +
, -
, and ^
are defined as follows:
+x is 0 + x
-x negation is 0 - x
^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned xand m = -1 for signed x
Integer overflow
For unsigned integer values, the operations +
, -
, *
, and <<
are computed modulo 2n, where n is the bit width of the unsigned integer’s type. Loosely speaking, these unsigned integer operations discard high bits upon overflow, and programs may rely on “wrap around”.
无符号整数(如 uint8
、uint32
、uint64
)的运算(加减乘和左移)在溢出时,不会报错或产生未定义行为,而是遵循 模运算(modular arithmetic) 规则:
- 模数:
2^n
(n
是类型的位宽,例如uint8
的n=8
,模数为256
)。 - 结果:运算结果会对
2^n
取模【%】,等价于保留最低n
位二进制数,直接丢弃高位。
result = (a op b) mod 2^n // op 为 +、-、* 或 <<
var a uint8 = 255 // 最大值:11111111
a = a + 1 // 256 (二进制 100000000),但 uint8 只有 8 位
fmt.Println(a) // 输出 0 (因为 256 % 256 = 0)
For signed integers, the operations +
, -
, *
, /
, and <<
may legally overflow and the resulting value exists and is deterministically defined by the signed integer representation, the operation, and its operands. Overflow does not cause a run-time panic. A compiler may not optimize code under the assumption that overflow does not occur. For instance, it may not assume that x < x + 1
is always true.
对于有符号整数(如 int
、int32
等),+
、-
、*
、/
和 <<
运算允许合法溢出,且结果值由有符号整数的二进制表示、运算符及其操作数共同确定。溢出不会引发运行时异常(panic)。但编译器不能基于“假设溢出不会发生”来优化代码。例如,它不能假设 x < x + 1
永远为真。
-
例如
int32
的最大值是2147483647
,如果+1
,会溢出到-2147483648
(二进制补码的“回绕”)。 -
无符号整数:溢出是明确定义的“模 2^n”行为(如
uint8
的255 + 1 = 0
)。 -
有符号整数:溢出是二进制补码的自然回绕(如
int8
的127 + 1 = -128
)。
Floating-point operators
For floating-point and complex numbers, +x
is the same as x
, while -x
is the negation of x
. The result of a floating-point or complex division by zero is not specified beyond the IEEE 754 standard; whether a run-time panic occurs is implementation-specific.
An implementation may combine multiple floating-point operations into a single fused operation【融合操作】, possibly across statements, and produce a result that differs from the value obtained by executing and rounding the instructions individually. An explicit floating-point type conversion rounds to the precision of the target type, preventing fusion that would discard that rounding.
Go 语言的实现(编译器或运行时)可能会将多个浮点数运算合并为一个融合操作(fused operation),甚至跨语句合并,并生成一个与逐条执行并单独舍入指令不同的结果。但显式的浮点数类型转换会按照目标类型的精度进行舍入,这种操作会阻止融合优化,从而避免因融合而丢失必要的舍入步骤。
什么是“融合操作”(Fused Operation)?
- 定义:
编译器或 CPU 可能会将多个浮点运算(如乘加运算a*b + c
)合并为一条硬件指令(如FMA
,Fused Multiply-Add),而不是分步计算a*b
和+c
。 - 优点:
- 提高性能(减少指令数)。
- 减少中间结果的舍入误差(因为融合操作只舍入一次,而不是两次)。
- 缺点:
- 结果可能与分步计算不同(因舍入次数不同)。
For instance, some architectures provide a “fused multiply and add” (FMA) instruction that computes x*y + z
without rounding the intermediate result x*y
. These examples show when a Go implementation can use that instruction:
// FMA allowed for computing r, because x*y is not explicitly rounded:
r = x*y + z
r = z; r += x*y
t = x*y; r = t + z
*p = x*y; r = *p + z
r = x*y + float64(z)// FMA disallowed for computing r, because it would omit rounding of x*y:
r = float64(x*y) + z
r = z; r += float64(x*y)
t = float64(x*y); r = t + z
String concatenation
Strings can be concatenated using the +
operator or the +=
assignment operator:
s := "hi" + string(c)
s += " and good bye"
String addition creates a new string by concatenating the operands.
Comparison operators
Comparison operators compare two operands and yield an untyped boolean value.
== equal
!= not equal
< less
<= less or equal
> greater
>= greater or equal
In any comparison, the first operand must be assignable to the type of the second operand, or vice versa.
The equality operators ==
and !=
apply to operands of comparable types【可比较类型】.
The ordering operators <
, <=
, >
, and >=
apply to operands of ordered types【有序类型】.
These terms and the result of the comparisons are defined as follows:
- Boolean types are comparable. Two boolean values are equal if they are either both
true
or bothfalse
. - Integer types are comparable and ordered. Two integer values are compared in the usual way.
- Floating-point types are comparable and ordered. Two floating-point values are compared as defined by the IEEE 754 standard.
- Complex types are comparable. Two complex values
u
andv
are equal if bothreal(u) == real(v)
andimag(u) == imag(v)
. - String types are comparable and ordered. Two string values are compared lexically byte-wise.
- Pointer types are comparable. Two pointer values are equal if they point to the same variable or if both have value
nil
. Pointers to distinct zero-size variables may or may not be equal. - Channel types are comparable. Two channel values are equal if they were created by the same call to
make
or if both have valuenil
. - Interface types that are not type parameters are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value
nil
. 【不是类型参数的接口类型是可以比较的!】 - A value
x
of non-interface typeX
and a valuet
of interface typeT
can be compared if typeX
is comparable andX
implementsT
. They are equal ift
’s dynamic type is identical toX
andt
’s dynamic value is equal tox
. - Struct types are comparable if all their field types are comparable. Two struct values are equal if their corresponding non-blank field values are equal. The fields are compared in source order, and comparison stops as soon as two field values differ (or all fields have been compared).
- Array types are comparable if their array element types are comparable. Two array values are equal if their corresponding element values are equal. The elements are compared in ascending index order, and comparison stops as soon as two element values differ (or all elements have been compared).
- Type parameters are comparable if they are strictly comparable (see below).
A comparison of two interface values with identical dynamic types causes a run-time panic if that type is not comparable. This behavior applies not only to direct interface value comparisons but also when comparing arrays of interface values or structs with interface-valued fields.
Slice, map, and function types are not comparable. However, as a special case, a slice, map, or function value may be compared to the predeclared identifier nil
. Comparison of pointer, channel, and interface values to nil
is also allowed and follows from the general rules above.
const c = 3 < 4 // c is the untyped boolean constant truetype MyBool bool
var x, y int
var (// The result of a comparison is an untyped boolean.// The usual assignment rules apply.b3 = x == y // b3 has type boolb4 bool = x == y // b4 has type boolb5 MyBool = x == y // b5 has type MyBool
)
A type is strictly comparable if it is comparable and not an interface type nor composed of interface types. 【接口类型不是严格可比较的!】Specifically:
- Boolean, numeric, string, pointer, and channel types are strictly comparable.
- Struct types are strictly comparable if all their field types are strictly comparable.
- Array types are strictly comparable if their array element types are strictly comparable.
- Type parameters are strictly comparable if all types in their type set are strictly comparable.
Logical operators
Logical operators apply to boolean values and yield a result of the same type as the operands. The left operand is evaluated, and then the right if the condition requires it.
&& conditional AND p && q is "if p then q else false"
|| conditional OR p || q is "if p then true else q"
! NOT !p is "not p"
Address operators
For an operand x
of type T
, the address operation &x
generates a pointer of type *T
to x
. The operand must be addressable, that is, either a variable, pointer indirection【指针解引用,也就是*p】, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x
may also be a (possibly parenthesized) composite literal. If the evaluation of x
would cause a run-time panic, then the evaluation of &x
does too.
For an operand x
of pointer type *T
, the pointer indirection【指针解引用】 *x
denotes the variable of type T
pointed to by x
. If x
is nil
, an attempt to evaluate *x
will cause a run-time panic.
&x
&a[f(2)]
&Point{2, 3}
*p
*pf(x)var x *int = nil
*x // causes a run-time panic
&*x // causes a run-time panic
Receive operator
For an operand ch
whose core type is a channel, the value of the receive operation <-ch
is the value received from the channel ch
. The channel direction must permit receive operations, and the type of the receive operation is the element type of the channel. The expression blocks until a value is available. Receiving from a nil
channel blocks forever. A receive operation on a closed channel can always proceed immediately, yielding the element type’s zero value after any previously sent values have been received.
v1 := <-ch
v2 = <-ch
f(<-ch)
<-strobe // wait until clock pulse and discard received value
A receive expression used in an assignment statement or initialization of the special form
x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
var x, ok T = <-ch
yields an additional untyped boolean result reporting whether the communication succeeded. The value of ok
is true
if the value received was delivered by a successful send operation to the channel, or false
if it is a zero value generated because the channel is closed and empty.
Conversions
A conversion changes the type of an expression to the type specified by the conversion. A conversion may appear literally in the source, or it may be implied by the context in which an expression appears.
An explicit conversion is an expression of the form T(x)
where T
is a type and x
is an expression that can be converted to type T
.
Conversion = Type "(" Expression [ "," ] ")" .
If the type starts with the operator *
or <-
, or if the type starts with the keyword func
and has no result list, it must be parenthesized when necessary to avoid ambiguity:
*Point(p) // same as *(Point(p))
(*Point)(p) // p is converted to *Point
<-chan int(c) // same as <-(chan int(c))
(<-chan int)(c) // c is converted to <-chan int
func()(x) // function signature func() x
(func())(x) // x is converted to func()
(func() int)(x) // x is converted to func() int
func() int(x) // x is converted to func() int (unambiguous)
A constant value x
can be converted to type T
if x
is representable by a value of T
. As a special case, an integer constant x
can be explicitly converted to a string type using the same rule as for non-constant x
.
在 Go 中,将整数(int
、rune
等)显式转换为字符串时,会将该整数解释为 Unicode 码点(code point),并生成对应的字符:
var x int = 65
s := string(x) // s 是 "A"(因为 65 是 'A' 的 Unicode 码点)
Converting a constant to a type that is not a type parameter yields a typed constant.
uint(iota) // iota value of type uint
float32(2.718281828) // 2.718281828 of type float32
complex128(1) // 1.0 + 0.0i of type complex128
float32(0.49999999) // 0.5 of type float32
float64(-1e-1000) // 0.0 of type float64
string('x') // "x" of type string
string(0x266c) // "♬" of type string
myString("foo" + "bar") // "foobar" of type myString
string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant
(*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
int(1.2) // illegal: 1.2 cannot be represented as an int
string(65.0) // illegal: 65.0 is not an integer constant
Converting a constant to a type parameter yields a non-constant value of that type, with the value represented as a value of the type argument that the type parameter is instantiated with. For example, given the function:
func f[P ~float32|~float64]() {… P(1.1) …
}
the conversion P(1.1)
results in a non-constant value of type P
and the value 1.1
is represented as a float32
or a float64
depending on the type argument for f
. Accordingly, if f
is instantiated with a float32
type, the numeric value of the expression P(1.1) + 1.2
will be computed with the same precision as the corresponding non-constant float32
addition.
A non-constant value x
can be converted to type T
in any of these cases:
-
x
is assignable toT
. - ignoring struct tags (see below),
x
’s type andT
are not type parameters but have identical underlying types. - ignoring struct tags (see below),
x
’s type andT
are pointer types that are not named types, and their pointer base types are not type parameters but have identical underlying types. -
x
’s type andT
are both integer or floating point types. -
x
’s type andT
are both complex types. -
x
is an integer or a slice of bytes or runes andT
is a string type. -
x
is a string andT
is a slice of bytes or runes. -
x
is a slice,T
is an array [Go 1.20] or a pointer to an array [Go 1.17], and the slice and array types have identical element types.
Additionally, if T
or x
’s type V
are type parameters, x
can also be converted to type T
if one of the following conditions applies:
- Both
V
andT
are type parameters and a value of each type inV
’s type set can be converted to each type inT
’s type set. - Only
V
is a type parameter and a value of each type inV
’s type set can be converted toT
. - Only
T
is a type parameter andx
can be converted to each type inT
’s type set.
Struct tags are ignored when comparing struct types for identity for the purpose of conversion:
type Person struct {Name stringAddress *struct {Street stringCity string}
}var data *struct {Name string `json:"name"`Address *struct {Street string `json:"street"`City string `json:"city"`} `json:"address"`
}var person = (*Person)(data) // ignoring tags, the underlying types are identical
Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x
and incur a run-time cost. All other conversions only change the type but not the representation of x
.
There is no linguistic mechanism to convert between pointers and integers. The package unsafe
implements this functionality under restricted circumstances.
Conversions between numeric types
For the conversion of non-constant numeric values, the following rules apply:
- When converting between integer types, if the value is a signed integer, it is sign extended to implicit infinite precision; otherwise it is zero extended. It is then truncated to fit in the result type’s size. For example, if
v := uint16(0x10F0)
, thenuint32(int8(v)) == 0xFFFFFFF0
. The conversion always yields a valid value; there is no indication of overflow.
如果被转换的值是有符号整数,则按符号位扩展至无限精度,(负数补 1
,正数补 0
)
如果是无符号整数,则补0扩展至无限精度。
然后会被截断以匹配目标类型的大小
- When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero).
- When converting an integer or floating-point number to a floating-point type, or a complex number to another complex type, the result value is rounded to the precision specified by the destination type. For instance, the value of a variable
x
of typefloat32
may be stored using additional precision beyond that of an IEEE 754 32-bit number, but float32(x) represents the result of roundingx
’s value to 32-bit precision. Similarly,x + 0.1
may use more than 32 bits of pecision, butfloat32(x + 0.1)
does not.
- 浮点数的“精度”是什么?
float32
:IEEE 754 单精度浮点数,有效数字约 7 位十进制。float64
:IEEE 754 双精度浮点数,有效数字约 15 位十进制。- 额外精度:
Go 允许在计算过程中临时使用更高精度(如硬件支持的 80 位扩展精度),但最终存储时必须匹配目标类型。
- 显式转换的作用
float32(x)
:强制将x
的值四舍五入到float32
的精度。- 未转换的表达式(如
x + 0.1
):可能使用更高精度计算,但结果仍需符合变量类型。
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
Conversions to and from a string type
-
Converting a slice of bytes to a string type yields a string whose successive bytes are the elements of the slice.
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø" string([]byte{}) // "" string([]byte(nil)) // ""type bytes []byte string(bytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"type myByte byte string([]myByte{'w', 'o', 'r', 'l', 'd', '!'}) // "world!" myString([]myByte{'\xf0', '\x9f', '\x8c', '\x8d'}) // "🌍"
-
Converting a slice of runes to a string type yields a string that is the concatenation of the individual rune values converted to strings.
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔" string([]rune{}) // "" string([]rune(nil)) // ""type runes []rune string(runes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"type myRune rune string([]myRune{0x266b, 0x266c}) // "\u266b\u266c" == "♫♬" myString([]myRune{0x1f30e}) // "\U0001f30e" == "🌎"
-
Converting a value of a string type to a slice of bytes type yields a non-nil slice whose successive elements are the bytes of the string. The capacity of the resulting slice is implementation-specific and may be larger than the slice length.
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []byte("") // []byte{}bytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}[]myByte("world!") // []myByte{'w', 'o', 'r', 'l', 'd', '!'} []myByte(myString("🌏")) // []myByte{'\xf0', '\x9f', '\x8c', '\x8f'}
-
Converting a value of a string type to a slice of runes type yields a slice containing the individual Unicode code points of the string. The capacity of the resulting slice is implementation-specific and may be larger than the slice length.
[]rune(myString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4} []rune("") // []rune{}runes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4}[]myRune("♫♬") // []myRune{0x266b, 0x266c} []myRune(myString("🌐")) // []myRune{0x1f310}
-
Finally, for historical reasons, an integer value may be converted to a string type. This form of conversion yields a string containing the (possibly multi-byte) UTF-8 representation of the Unicode code point with the given integer value. Values outside the range of valid Unicode code points are converted to “\uFFFD”.
string('a') // "a" string(65) // "A" string('\xf8') // "\u00f8" == "ø" == "\xc3\xb8" string(-1) // "\ufffd" == "\xef\xbf\xbd"type myString string myString('\u65e5') // "\u65e5" == "日" == "\xe6\x97\xa5"
Note: This form of conversion may eventually be removed from the language. The
go vet
tool flags certain integer-to-string conversions as potential errors. Library functions such asutf8.AppendRune
orutf8.EncodeRune
should be used instead.
Conversions from slice to array or array pointer
Converting a slice to an array yields an array containing the elements of the underlying array of the slice. Similarly, converting a slice to an array pointer yields a pointer to the underlying array of the slice. In both cases, if the length of the slice is less than the length of the array, a run-time panic occurs.
s := make([]byte, 2, 4)a0 := [0]byte(s)
a1 := [1]byte(s[1:]) // a1[0] == s[1]
a2 := [2]byte(s) // a2[0] == s[0]
a4 := [4]byte(s) // panics: len([4]byte) > len(s)s0 := (*[0]byte)(s) // s0 != nil
s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]
s2 := (*[2]byte)(s) // &s2[0] == &s[0]
s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s)var t []string
t0 := [0]string(t) // ok for nil slice t
t1 := (*[0]string)(t) // t1 == nil
t2 := (*[1]string)(t) // panics: len([1]string) > len(t)u := make([]byte, 0)
u0 := (*[0]byte)(u) // u0 != nil
Constant expressions
Constant expressions may contain only constant operands and are evaluated at compile time.
Untyped boolean, numeric, and string constants may be used as operands wherever it is legal to use an operand of boolean, numeric, or string type, respectively.
A constant comparison always yields an untyped boolean constant.
If the left operand of a constant shift expression 【移位表达式】is an untyped constant, the result is an integer constant; otherwise it is a constant of the same type as the left operand, which must be of integer type.
Any other operation on untyped constants results in an untyped constant of the same kind; that is, a boolean, integer, floating-point, complex, or string constant.
If the untyped operands of a binary operation (other than a shift) are of different kinds, the result is of the operand’s kind that appears later in this list: integer, rune, floating-point, complex. For example, an untyped integer constant divided by an untyped complex constant yields an untyped complex constant.
const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant)
const b = 15 / 4 // b == 3 (untyped integer constant)
const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant)
const Θ float64 = 3/2 // Θ == 1.0 (type float64, 3/2 is integer division)
const Π float64 = 3/2. // Π == 1.5 (type float64, 3/2. is float division)
const d = 1 << 3.0 // d == 8 (untyped integer constant)
const e = 1.0 << 3 // e == 8 (untyped integer constant)
const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32)
const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant)
const h = "foo" > "bar" // h == true (untyped boolean constant)
const j = true // j == true (untyped boolean constant)
const k = 'w' + 1 // k == 'x' (untyped rune constant)
const l = "hi" // l == "hi" (untyped string constant)
const m = string(k) // m == "x" (type string)
const Σ = 1 - 0.707i // (untyped complex constant)
const Δ = Σ + 2.0e-4 // (untyped complex constant)
const Φ = iota*1i - 1/1i // (untyped complex constant)
Applying the built-in function complex
to untyped integer, rune, or floating-point constants yields an untyped complex constant.
const ic = complex(0, c) // ic == 3.75i (untyped complex constant)
const iΘ = complex(0, Θ) // iΘ == 1i (type complex128)
Constant expressions are always evaluated exactly; intermediate values and the constants themselves may require precision significantly larger than supported by any predeclared type in the language. The following are legal declarations:
const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant)
const Four int8 = Huge >> 98 // Four == 4 (type int8)
Go 语言中的常量表达式(constant expressions)在编译时会完全精确计算,不会出现精度损失。计算过程中所需的中间值(包括常量本身)的精度可能远超 Go 任何预定义类型(如 int64
、float64
)的支持范围。
The divisor of a constant division or remainder operation must not be zero:
3.14 / 0.0 // illegal: division by zero
The values of typed constants must always be accurately representable by values of the constant type. The following constant expressions are illegal:
uint(-1) // -1 cannot be represented as a uint
int(3.14) // 3.14 cannot be represented as an int
int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64
Four * 300 // operand 300 cannot be represented as an int8 (type of Four)
Four * 100 // product 400 cannot be represented as an int8 (type of Four)
The mask used by the unary bitwise complement operator ^
【一元按位取反运算符】matches the rule for non-constants: the mask is all 1s for unsigned constants and -1 for signed and untyped constants.
在计算机中,按位取反(^x
) 和 掩码(mask) 紧密相关,因为按位取反的本质是通过一个全1的掩码进行异或运算(XOR
)实现的。
^ x = mask ^ x
mask
是一个所有二进制位均为1
的数,其具体值取决于操作数x
的类型。^
是异或运算符(相同为0
,不同为1
)。
掩码的取值由操作数 x
的类型决定:
操作数类型 | 掩码(二进制) | 掩码(十六进制/十进制) | 示例 |
---|---|---|---|
无符号类型 | 全 1 | 0xFF...F (最大值) | ^uint8(0) → 0xFF |
有符号类型 | 全 1 (即 -1 ) | -1 (补码表示全 1 ) | ^int8(0) → -1 (0xFF ) |
无类型常量 | 全 1 (即 -1 ) | 默认按 int 处理 | ^1 → -2 (-1 ^ 1 ) |
^1 // untyped integer constant, equal to -2
uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8
^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
int8(^1) // same as int8(-2)
^int8(1) // same as -1 ^ int8(1) = -2
Implementation restriction: A compiler may use rounding while computing untyped floating-point or complex constant expressions; see the implementation restriction in the section on constants. This rounding may cause a floating-point constant expression to be invalid in an integer context, even if it would be integral when calculated using infinite precision, and vice versa.
Order of evaluation
At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, receive operations, and binary logical operations are evaluated in lexical left-to-right order.
For example, in the (function-local) assignment
y[f()], ok = g(z || h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order f()
, h()
(if z
evaluates to false), i()
, j()
, <-c
, g()
, and k()
. However, the order of those events compared to the evaluation and indexing of x
and the evaluation of y
and z
is not specified, except as required lexically. For instance, g
cannot be called before its arguments are evaluated.
a := 1
f := func() int { a++; return a }
x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
At package level, initialization dependencies override the left-to-right rule for individual initialization expressions, but not for operands within each expression:
var a, b, c = f() + v(), g(), sqr(u()) + v()func f() int { return c }
func g() int { return a }
func sqr(x int) int { return x*x }// functions u and v are independent of all other variables and functions
The function calls happen in the order u()
, sqr()
, v()
, f()
, v()
, and g()
.
a依赖c
b依赖a
所以初始化顺序是c a b。
Floating-point operations within a single expression are evaluated according to the associativity【结合性】 of the operators. Explicit parentheses affect the evaluation by overriding the default associativity. In the expression x + (y + z)
the addition y + z
is performed before adding x
.