|
|
@@ -22,17 +22,21 @@
|
|
|
|
|
|
示例:
|
|
|
|
|
|
- var aVar = 10
|
|
|
- aVar == 5 -> false
|
|
|
- aVar == 10 -> true
|
|
|
+```go
|
|
|
+var aVar = 10
|
|
|
+aVar == 5 -> false
|
|
|
+aVar == 10 -> true
|
|
|
+```
|
|
|
|
|
|
当不等运算符两边的值是不同的时候会返回 true,否则返回 false。
|
|
|
|
|
|
示例:
|
|
|
|
|
|
- var aVar = 10
|
|
|
- aVar != 5 -> true
|
|
|
- aVar != 10 -> false
|
|
|
+```go
|
|
|
+var aVar = 10
|
|
|
+aVar != 5 -> true
|
|
|
+aVar != 10 -> false
|
|
|
+```
|
|
|
|
|
|
Go 对于值之间的比较有非常严格的限制,只有两个类型相同的值才可以进行比较,如果值的类型是接口(interface,第 11 章),它们也必须都实现了相同的接口。如果其中一个值是常量,那么另外一个值的类型必须和该常量类型相兼容的。如果以上条件都不满足,则其中一个值的类型必须在被转换为和另外一个值的类型相同之后才可以进行比较。
|
|
|
|
|
|
@@ -44,26 +48,32 @@ Go 语言中包含以下逻辑运算符:
|
|
|
|
|
|
非运算符:`!`
|
|
|
|
|
|
- !T -> false
|
|
|
- !F -> true
|
|
|
+```go
|
|
|
+!T -> false
|
|
|
+!F -> true
|
|
|
+```
|
|
|
|
|
|
非运算符用于取得和布尔值相反的结果。
|
|
|
|
|
|
和运算符:`&&`
|
|
|
|
|
|
- T && T -> true
|
|
|
- T && F -> false
|
|
|
- F && T -> false
|
|
|
- F && F -> false
|
|
|
+```go
|
|
|
+T && T -> true
|
|
|
+T && F -> false
|
|
|
+F && T -> false
|
|
|
+F && F -> false
|
|
|
+```
|
|
|
|
|
|
只有当两边的值都为 true 的时候,和运算符的结果才是 true。
|
|
|
|
|
|
或运算符:`||`
|
|
|
|
|
|
- T || T -> true
|
|
|
- T || F -> true
|
|
|
- F || T -> true
|
|
|
- F || F -> false
|
|
|
+```go
|
|
|
+T || T -> true
|
|
|
+T || F -> true
|
|
|
+F || T -> true
|
|
|
+F || F -> false
|
|
|
+```
|
|
|
|
|
|
只有当两边的值都为 false 的时候,或运算符的结果才是 false,其中任意一边的值为 true 就能够使得该表达式的结果为 true。
|
|
|
|
|
|
@@ -127,17 +137,19 @@ float32 精确到小数点后 7 位,float64 精确到小数点后 15 位。由
|
|
|
|
|
|
Go 中不允许不同类型之间的混合使用,但是对于常量的类型限制非常少,因此允许常量之间的混合使用,下面这个程序很好地解释了这个现象(该程序无法通过编译):
|
|
|
|
|
|
-Example 4.8 [type_mixing.go](examples/chapter_4/type_mixing.go)
|
|
|
+示例 4.8 [type_mixing.go](examples/chapter_4/type_mixing.go)
|
|
|
|
|
|
- package main
|
|
|
-
|
|
|
- func main() {
|
|
|
- var a int
|
|
|
- var b int32
|
|
|
- a = 15
|
|
|
- b = a + a // 编译错误
|
|
|
- b = b + 5 // 因为 5 是常量,所以可以通过编译
|
|
|
- }
|
|
|
+```go
|
|
|
+package main
|
|
|
+
|
|
|
+func main() {
|
|
|
+ var a int
|
|
|
+ var b int32
|
|
|
+ a = 15
|
|
|
+ b = a + a // 编译错误
|
|
|
+ b = b + 5 // 因为 5 是常量,所以可以通过编译
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
如果你尝试编译该程序,则将得到编译错误 `cannot use a + a (type int) as type int32 in assignment`。
|
|
|
|
|
|
@@ -145,26 +157,31 @@ Example 4.8 [type_mixing.go](examples/chapter_4/type_mixing.go)
|
|
|
|
|
|
下面这个程序展示了通过显示转换来避免这个问题(第 4.2 节)。
|
|
|
|
|
|
-Example 4.9 [casting.go](examples/chapter_4/casting.go)
|
|
|
+示例 4.9 [casting.go](examples/chapter_4/casting.go)
|
|
|
|
|
|
- package main
|
|
|
+```go
|
|
|
+package main
|
|
|
|
|
|
- import “fmt”
|
|
|
+import “fmt”
|
|
|
|
|
|
- func main() {
|
|
|
- var n int16 = 34
|
|
|
- var m int32
|
|
|
- // compiler error: cannot use n (type int16) as type int32 in assignment
|
|
|
- //m = n
|
|
|
- m = int32(n)
|
|
|
-
|
|
|
- fmt.Printf(“32 bit int is: %d\n”, m)
|
|
|
- fmt.Printf(“16 bit int is: %d\n”, n)
|
|
|
- }
|
|
|
+func main() {
|
|
|
+ var n int16 = 34
|
|
|
+ var m int32
|
|
|
+ // compiler error: cannot use n (type int16) as type int32 in assignment
|
|
|
+ //m = n
|
|
|
+ m = int32(n)
|
|
|
|
|
|
- // the output is:
|
|
|
- 32 bit int is: 34
|
|
|
- 16 bit int is: 34
|
|
|
+ fmt.Printf(“32 bit int is: %d\n”, m)
|
|
|
+ fmt.Printf(“16 bit int is: %d\n”, n)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+输出:
|
|
|
+
|
|
|
+```
|
|
|
+32 bit int is: 34
|
|
|
+16 bit int is: 34
|
|
|
+```
|
|
|
|
|
|
**格式化说明符**
|
|
|
|
|
|
@@ -176,25 +193,29 @@ Example 4.9 [casting.go](examples/chapter_4/casting.go)
|
|
|
|
|
|
当进行类似 `a32bitInt = int32(a32Float)` 的转换时,小数点后的数字将被丢弃。这种情况一般发生当从取值范围较大的类型转换为取值范围较小的类型时,或者你可以写一个专门用于处理类型转换的函数来确保没有发生精度的丢失。下面这个例子展示如何安全地从 int 型转换为 int8:
|
|
|
|
|
|
- func Uint8FromInt(n int) (uint8, error) {
|
|
|
- if 0 <= n && n <= math.MaxUint8 { // conversion is safe
|
|
|
- return uint8(n), nil
|
|
|
- }
|
|
|
- return 0, fmt.Errorf(“%d is out of the uint8 range”, n)
|
|
|
+```go
|
|
|
+func Uint8FromInt(n int) (uint8, error) {
|
|
|
+ if 0 <= n && n <= math.MaxUint8 { // conversion is safe
|
|
|
+ return uint8(n), nil
|
|
|
}
|
|
|
+ return 0, fmt.Errorf(“%d is out of the uint8 range”, n)
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
或者安全地从 float64 转换为 int:
|
|
|
|
|
|
- func IntFromFloat64(x float64) int {
|
|
|
- if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
|
|
|
- whole, fraction := math.Modf(x)
|
|
|
- if fraction >= 0.5 {
|
|
|
- whole++
|
|
|
- }
|
|
|
- return int(whole)
|
|
|
+```go
|
|
|
+func IntFromFloat64(x float64) int {
|
|
|
+ if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
|
|
|
+ whole, fraction := math.Modf(x)
|
|
|
+ if fraction >= 0.5 {
|
|
|
+ whole++
|
|
|
}
|
|
|
- panic(fmt.Sprintf(“%g is out of the int32 range”, x))
|
|
|
+ return int(whole)
|
|
|
}
|
|
|
+ panic(fmt.Sprintf(“%g is out of the int32 range”, x))
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
不过如果你实际存的数字超出你要转换到的类型的取值范围的话,则会引发 panic(第 13.2 节)。
|
|
|
|
|
|
@@ -211,13 +232,17 @@ Go 拥有以下复数类型:
|
|
|
|
|
|
示例:
|
|
|
|
|
|
- var c1 complex64 = 5 + 10i
|
|
|
- fmt.Printf(“The value is: %v”, c1)
|
|
|
- // 输出: 5 + 10i
|
|
|
+```go
|
|
|
+var c1 complex64 = 5 + 10i
|
|
|
+fmt.Printf(“The value is: %v”, c1)
|
|
|
+// 输出: 5 + 10i
|
|
|
+```
|
|
|
|
|
|
如果 `re` 和 `im` 的类型均为 float32,那么类型为 complex64 的复数 c 可以通过以下方式来获得:
|
|
|
|
|
|
- c = complex(re, im)
|
|
|
+```go
|
|
|
+c = complex(re, im)
|
|
|
+```
|
|
|
|
|
|
函数 `real(c)` 和 `imag(c)` 可以分别获得相应的实数和虚数部分。
|
|
|
|
|
|
@@ -275,8 +300,8 @@ Go 拥有以下复数类型:
|
|
|
- 用法:`bitP << n`。
|
|
|
- `bitP` 的位向左移动 n 位,右侧空白部分使用 0 填充;如果 n 等于 2,则结果是 2 的相应倍数,即 2 的 n 次方。例如:
|
|
|
|
|
|
- 1 << 10 // 等于 1 KB
|
|
|
- 1 << 20 // 等于 1 MB
|
|
|
+ 1 << 10 // 等于 1 KB
|
|
|
+ 1 << 20 // 等于 1 MB
|
|
|
1 << 30 // 等于 1 GB
|
|
|
|
|
|
- 位右移 `>>`:
|
|
|
@@ -290,29 +315,33 @@ Go 拥有以下复数类型:
|
|
|
|
|
|
使用位左移与 iota 计数配合可优雅地实现存储单位的常量枚举:
|
|
|
|
|
|
- type ByteSize float64
|
|
|
- const (
|
|
|
- _ = iota // 通过赋值给空白标识符来忽略值
|
|
|
- KB ByteSize = 1<<(10*iota)
|
|
|
- MB
|
|
|
- GB
|
|
|
- TB
|
|
|
- PB
|
|
|
- EB
|
|
|
- ZB
|
|
|
- YB
|
|
|
- )
|
|
|
+```go
|
|
|
+type ByteSize float64
|
|
|
+const (
|
|
|
+ _ = iota // 通过赋值给空白标识符来忽略值
|
|
|
+ KB ByteSize = 1<<(10*iota)
|
|
|
+ MB
|
|
|
+ GB
|
|
|
+ TB
|
|
|
+ PB
|
|
|
+ EB
|
|
|
+ ZB
|
|
|
+ YB
|
|
|
+)
|
|
|
+```
|
|
|
|
|
|
**在通讯中使用位左移表示标识的用例**
|
|
|
|
|
|
- type BitFlag int
|
|
|
- const (
|
|
|
- Active BitFlag = 1 << iota // 1 << 0 == 1
|
|
|
- Send // 1 << 1 == 2
|
|
|
- Receive // 1 << 2 == 4
|
|
|
- )
|
|
|
+```go
|
|
|
+type BitFlag int
|
|
|
+const (
|
|
|
+ Active BitFlag = 1 << iota // 1 << 0 == 1
|
|
|
+ Send // 1 << 1 == 2
|
|
|
+ Receive // 1 << 2 == 4
|
|
|
+)
|
|
|
|
|
|
- flag := Active | Send // == 3
|
|
|
+flag := Active | Send // == 3
|
|
|
+```
|
|
|
|
|
|
### 4.5.2.4 逻辑运算符
|
|
|
|
|
|
@@ -320,7 +349,9 @@ Go 中拥有以下逻辑运算符:`==`、`!=`(第 4.5.1 节)、`<`、`<=`
|
|
|
|
|
|
它们之所以被称为逻辑运算符是因为它们的运算结果总是为布尔值 `bool`。例如:
|
|
|
|
|
|
- b3:= 10 > 5 // b3 is true
|
|
|
+```go
|
|
|
+b3:= 10 > 5 // b3 is true
|
|
|
+```
|
|
|
|
|
|
### 4.5.2.5 算术运算符
|
|
|
|
|
|
@@ -353,31 +384,33 @@ Go 中拥有以下逻辑运算符:`==`、`!=`(第 4.5.1 节)、`<`、`<=`
|
|
|
|
|
|
一些像游戏或者统计学类的应用需要用到随机数。`rand` 包实现了伪随机数的生成。
|
|
|
|
|
|
-Example 4.10 [random.go](examples/chapter_4/random.go) 演示了如何生成 10 个非负随机数:
|
|
|
+示例 4.10 [random.go](examples/chapter_4/random.go) 演示了如何生成 10 个非负随机数:
|
|
|
|
|
|
- package main
|
|
|
- import (
|
|
|
- "fmt"
|
|
|
- "math/rand"
|
|
|
- "time"
|
|
|
- )
|
|
|
+```go
|
|
|
+package main
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "math/rand"
|
|
|
+ "time"
|
|
|
+)
|
|
|
|
|
|
- func main() {
|
|
|
- for i := 0; i < 10; i++ {
|
|
|
- a := rand.Int()
|
|
|
- fmt.Printf("%d / ", a)
|
|
|
- }
|
|
|
- for i := 0; i < 5; i++ {
|
|
|
- r := rand.Intn(8)
|
|
|
- fmt.Printf("%d / ", r)
|
|
|
- }
|
|
|
- fmt.Println()
|
|
|
- timens := int64(time.Now().Nanosecond())
|
|
|
- rand.Seed(timens)
|
|
|
- for i := 0; i < 10; i++ {
|
|
|
- fmt.Printf("%2.2f / ", 100*rand.Float32())
|
|
|
- }
|
|
|
+func main() {
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
+ a := rand.Int()
|
|
|
+ fmt.Printf("%d / ", a)
|
|
|
}
|
|
|
+ for i := 0; i < 5; i++ {
|
|
|
+ r := rand.Intn(8)
|
|
|
+ fmt.Printf("%d / ", r)
|
|
|
+ }
|
|
|
+ fmt.Println()
|
|
|
+ timens := int64(time.Now().Nanosecond())
|
|
|
+ rand.Seed(timens)
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
+ fmt.Printf("%2.2f / ", 100*rand.Float32())
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
可能的输出:
|
|
|
|
|
|
@@ -410,18 +443,20 @@ Example 4.10 [random.go](examples/chapter_4/random.go) 演示了如何生成 10
|
|
|
|
|
|
在 `type TZ int` 中,TZ 就是 int 类型的新名称(用于表示程序中的时区),然后就可以使用 TZ 来操作 int 类型的数据。
|
|
|
|
|
|
-Example 4.11 [type.go](examples/chapter_4/type.go)
|
|
|
+示例 4.11 [type.go](examples/chapter_4/type.go)
|
|
|
|
|
|
- package main
|
|
|
- import “fmt”
|
|
|
+```go
|
|
|
+package main
|
|
|
+import “fmt”
|
|
|
|
|
|
- type TZ int
|
|
|
+type TZ int
|
|
|
|
|
|
- func main() {
|
|
|
- var a, b TZ = 3, 4
|
|
|
- c := a + b
|
|
|
- fmt.Printf(“c has the value: %d”, c) // 输出:c has the value: 7
|
|
|
- }
|
|
|
+func main() {
|
|
|
+ var a, b TZ = 3, 4
|
|
|
+ c := a + b
|
|
|
+ fmt.Printf(“c has the value: %d”, c) // 输出:c has the value: 7
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
实际上,类型别名得到的新类型并非和原类型完全相同,新类型不会拥有原类型所附带的方法(第 10 章);TZ 可以自定义一个方法用来输出更加人性化的时区信息。
|
|
|
|
|
|
@@ -433,7 +468,9 @@ Example 4.11 [type.go](examples/chapter_4/type.go)
|
|
|
|
|
|
在 ASCII 码表中,A 的值是 65,而使用 16 进制表示则为 41,所以下面的写法是等效的:
|
|
|
|
|
|
- var ch byte = 65 或 var ch byte = ‘\x41’
|
|
|
+```go
|
|
|
+var ch byte = 65 或 var ch byte = ‘\x41’
|
|
|
+```
|
|
|
|
|
|
(`\x` 总是紧跟着长度为 2 的 16 进制数)
|
|
|
|
|
|
@@ -445,15 +482,17 @@ Example 4.11 [type.go](examples/chapter_4/type.go)
|
|
|
|
|
|
因为 Unicode 至少占用 2 个字节,所以我们使用 `int16` 或者 `int` 类型来表示。如果需要使用到 4 字节,则会加上 `\U` 前缀;前缀 `\u` 则总是紧跟着长度为 4 的 16 进制数,前缀 `\U` 紧跟着长度为 8 的 16 进制数。
|
|
|
|
|
|
-Example 4.12 [char.go](examples/chapter_4/char.go)
|
|
|
+示例 4.12 [char.go](examples/chapter_4/char.go)
|
|
|
|
|
|
- var ch int = ‘\u0041’
|
|
|
- var ch2 int = ‘\u03B2’
|
|
|
- var ch3 int = ‘\U00101234’
|
|
|
- fmt.Printf(“%d - %d - %d\n”, ch, ch2, ch3) // integer
|
|
|
- fmt.Printf(“%c - %c - %c\n”, ch, ch2, ch3) // character
|
|
|
- fmt.Printf(“%X - %X - %X\n”, ch, ch2, ch3) // UTF-8 bytes
|
|
|
- fmt.Printf(“%U - %U - %U”, ch, ch2, ch3) // UTF-8 code point
|
|
|
+```go
|
|
|
+var ch int = ‘\u0041’
|
|
|
+var ch2 int = ‘\u03B2’
|
|
|
+var ch3 int = ‘\U00101234’
|
|
|
+fmt.Printf(“%d - %d - %d\n”, ch, ch2, ch3) // integer
|
|
|
+fmt.Printf(“%c - %c - %c\n”, ch, ch2, ch3) // character
|
|
|
+fmt.Printf(“%X - %X - %X\n”, ch, ch2, ch3) // UTF-8 bytes
|
|
|
+fmt.Printf(“%U - %U - %U”, ch, ch2, ch3) // UTF-8 code point
|
|
|
+```
|
|
|
|
|
|
输出:
|
|
|
|
|
|
@@ -466,9 +505,9 @@ Example 4.12 [char.go](examples/chapter_4/char.go)
|
|
|
|
|
|
包 `unicode` 包含了一些针对测试字符的非常有用的函数(其中 `ch` 代表字符):
|
|
|
|
|
|
- 判断是否为字母: unicode.IsLetter(ch)
|
|
|
- 判断是否为数字: unicode.IsDigit(ch)
|
|
|
- 判断是否为空白符号: unicode.IsSpace(ch)
|
|
|
+- 判断是否为字母:`unicode.IsLetter(ch)`
|
|
|
+- 判断是否为数字:`unicode.IsDigit(ch)`
|
|
|
+- 判断是否为空白符号:`unicode.IsSpace(ch)`
|
|
|
|
|
|
这些函数返回一个布尔值。包 `utf8` 拥有更多与 rune 相关的函数。
|
|
|
|