mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 19:41:43 +08:00
精校:4.8-5.1
This commit is contained in:
@@ -273,7 +273,7 @@ func main() {
|
||||
GO1 - The ABC of Go - 25 -
|
||||
sl2 joined by ;: GO1;The ABC of Go;25
|
||||
|
||||
其它有关字符串操作的文档请参阅官方文档 [http://golang.org/pkg/strings/](http://golang.org/pkg/strings/)( **译者注:国内用户可访问 [该页面](http://docs.studygolang.com/pkg/strings/)** )。
|
||||
其它有关字符串操作的文档请参阅 [官方文档](http://golang.org/pkg/strings/)( **译者注:国内用户可访问 [该页面](http://docs.studygolang.com/pkg/strings/)** )。
|
||||
|
||||
## 4.7.11 从字符串中读取内容
|
||||
|
||||
@@ -341,7 +341,7 @@ func main() {
|
||||
|
||||
在第 5.1 节,我们将会利用 if 语句来对可能出现的错误进行分类处理。
|
||||
|
||||
更多有关该包的讨论,请参阅官方文档 [http://golang.org/pkg/strconv/](http://golang.org/pkg/strconv/)( **译者注:国内用户可访问 [该页面](http://docs.studygolang.com/pkg/strconv/)** )。
|
||||
更多有关该包的讨论,请参阅 [官方文档](http://golang.org/pkg/strconv/)( **译者注:国内用户可访问 [该页面](http://docs.studygolang.com/pkg/strconv/)** )。
|
||||
|
||||
## 链接
|
||||
|
||||
|
@@ -10,43 +10,47 @@ Duration 类型表示两个连续时刻所相差的纳秒数,类型为 int64
|
||||
|
||||
一般的格式化设计是通过对于一个标准时间的格式化描述来展现的,这听起来很奇怪,但看下面这个例子你就会一目了然:
|
||||
|
||||
fmt.Println(t.Format("02 Jan 2006 15:04"))
|
||||
```go
|
||||
fmt.Println(t.Format("02 Jan 2006 15:04"))
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
21 Jul 2011 10:31
|
||||
|
||||
其它有关时间操作的文档请参阅官方文档 [http://golang.org/pkg/time/](http://golang.org/pkg/time/)( **译者注:国内用户可访问 [http://docs.studygolang.com/pkg/time/](http://docs.studygolang.com/pkg/time/)** )。
|
||||
其它有关时间操作的文档请参阅 [官方文档](http://golang.org/pkg/time/)( **译者注:国内用户可访问 [该页面](http://docs.studygolang.com/pkg/time/)** )。
|
||||
|
||||
Example 4.20 [time.go](examples/chapter_4/time.go)
|
||||
示例 4.20 [time.go](examples/chapter_4/time.go)
|
||||
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var week time.Duration
|
||||
func main() {
|
||||
t := time.Now()
|
||||
fmt.Println(t) // e.g. Wed Dec 21 09:52:14 +0100 RST 2011
|
||||
fmt.Printf("%02d.%02d.%4d\n", t.Day(), t.Month(), t.Year())
|
||||
// 21.12.2011
|
||||
t = time.Now().UTC()
|
||||
fmt.Println(t) // Wed Dec 21 08:52:14 +0000 UTC 2011
|
||||
fmt.Println(time.Now()) // Wed Dec 21 09:52:14 +0100 RST 2011
|
||||
// calculating times:
|
||||
week = 60 * 60 * 24 * 7 * 1e9 // must be in nanosec
|
||||
week_from_now := t.Add(week)
|
||||
fmt.Println(week_from_now) // Wed Dec 28 08:52:14 +0000 UTC 2011
|
||||
// formatting times:
|
||||
fmt.Println(t.Format(time.RFC822)) // 21 Dec 11 0852 UTC
|
||||
fmt.Println(t.Format(time.ANSIC)) // Wed Dec 21 08:56:34 2011
|
||||
fmt.Println(t.Format("02 Jan 2006 15:04")) // 21 Dec 2011 08:52
|
||||
s := t.Format("20060102")
|
||||
fmt.Println(t, "=>", s)
|
||||
// Wed Dec 21 08:52:14 +0000 UTC 2011 => 20111221
|
||||
}
|
||||
var week time.Duration
|
||||
func main() {
|
||||
t := time.Now()
|
||||
fmt.Println(t) // e.g. Wed Dec 21 09:52:14 +0100 RST 2011
|
||||
fmt.Printf("%02d.%02d.%4d\n", t.Day(), t.Month(), t.Year())
|
||||
// 21.12.2011
|
||||
t = time.Now().UTC()
|
||||
fmt.Println(t) // Wed Dec 21 08:52:14 +0000 UTC 2011
|
||||
fmt.Println(time.Now()) // Wed Dec 21 09:52:14 +0100 RST 2011
|
||||
// calculating times:
|
||||
week = 60 * 60 * 24 * 7 * 1e9 // must be in nanosec
|
||||
week_from_now := t.Add(week)
|
||||
fmt.Println(week_from_now) // Wed Dec 28 08:52:14 +0000 UTC 2011
|
||||
// formatting times:
|
||||
fmt.Println(t.Format(time.RFC822)) // 21 Dec 11 0852 UTC
|
||||
fmt.Println(t.Format(time.ANSIC)) // Wed Dec 21 08:56:34 2011
|
||||
fmt.Println(t.Format("02 Jan 2006 15:04")) // 21 Dec 2011 08:52
|
||||
s := t.Format("20060102")
|
||||
fmt.Println(t, "=>", s)
|
||||
// Wed Dec 21 08:52:14 +0000 UTC 2011 => 20111221
|
||||
}
|
||||
```
|
||||
|
||||
输出的结果已经写在每行 `//` 的后面。
|
||||
|
||||
|
@@ -8,14 +8,18 @@
|
||||
|
||||
Go 语言的取地址符是 `&`,放到一个变量前使用就会返回相应变量的内存地址。
|
||||
|
||||
下面的代码片段(Example 4.9 [pointer.go](examples/chapter_4/pointer.go))可能输出 `An integer: 5, its location in memory: 0x6b0820`(这个值随着你每次运行程序而变化)。
|
||||
下面的代码片段(示例 4.9 [pointer.go](examples/chapter_4/pointer.go))可能输出 `An integer: 5, its location in memory: 0x6b0820`(这个值随着你每次运行程序而变化)。
|
||||
|
||||
var i1 = 5
|
||||
fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)
|
||||
```go
|
||||
var i1 = 5
|
||||
fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)
|
||||
```
|
||||
|
||||
这个地址可以存储在一个叫做指针的特殊数据类型中,在本例中这是一个指向 int 的指针,即 `i1`:此处使用 *int 表示。如果我们想调用指针 intP,我们可以这样声明它:
|
||||
|
||||
var intP *int
|
||||
```go
|
||||
var intP *int
|
||||
```
|
||||
|
||||
然后使用 `intP = &i1` 是合法的,此时 intP 指向 i1。
|
||||
|
||||
@@ -39,17 +43,19 @@ intP 存储了 i1 的内存地址;它指向了 i1 的位置,它引用了变
|
||||
|
||||
现在,我们应当能理解 pointer.go 中的整个程序和他的输出:
|
||||
|
||||
Example 4.21 [pointer.go](examples/chapter_4/pointer.go):
|
||||
示例 4.21 [pointer.go](examples/chapter_4/pointer.go):
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
var i1 = 5
|
||||
fmt.Printf("An integer: %d, its location in memory: %p\n", i1, &i1)
|
||||
var intP *int
|
||||
intP = &i1
|
||||
fmt.Printf("The value at memory location %p is %d\n", intP, *intP)
|
||||
}
|
||||
```go
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
var i1 = 5
|
||||
fmt.Printf("An integer: %d, its location in memory: %p\n", i1, &i1)
|
||||
var intP *int
|
||||
intP = &i1
|
||||
fmt.Printf("The value at memory location %p is %d\n", intP, *intP)
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
@@ -64,18 +70,20 @@ Example 4.21 [pointer.go](examples/chapter_4/pointer.go):
|
||||
|
||||
它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)。
|
||||
|
||||
Example 4.22 [string_pointer.go](examples/chapter_4/string_pointer.go)
|
||||
示例 4.22 [string_pointer.go](examples/chapter_4/string_pointer.go)
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
s := "good bye"
|
||||
var p *string = &s
|
||||
*p = "ciao"
|
||||
fmt.Printf("Here is the pointer p: %p\n", p) // prints address
|
||||
fmt.Printf("Here is the string *p: %s\n", *p) // prints string
|
||||
fmt.Printf("Here is the string s: %s\n", s) // prints same string
|
||||
}
|
||||
```go
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
s := "good bye"
|
||||
var p *string = &s
|
||||
*p = "ciao"
|
||||
fmt.Printf("Here is the pointer p: %p\n", p) // prints address
|
||||
fmt.Printf("Here is the string *p: %s\n", *p) // prints string
|
||||
fmt.Printf("Here is the string s: %s\n", s) // prints same string
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
@@ -93,9 +101,11 @@ Example 4.22 [string_pointer.go](examples/chapter_4/string_pointer.go)
|
||||
|
||||
你不能得到一个文字或常量的地址,例如:
|
||||
|
||||
const i = 5
|
||||
ptr := &i //error: cannot take the address of i
|
||||
ptr2 := &10 //error: cannot take the address of 10
|
||||
```go
|
||||
const i = 5
|
||||
ptr := &i //error: cannot take the address of i
|
||||
ptr2 := &10 //error: cannot take the address of 10
|
||||
```
|
||||
|
||||
所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如:`pointer+2`,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和 VB.NET 中的引用。
|
||||
|
||||
@@ -111,15 +121,17 @@ Example 4.22 [string_pointer.go](examples/chapter_4/string_pointer.go)
|
||||
|
||||
对一个空指针的反向引用是不合法的,并且会使程序崩溃:
|
||||
|
||||
Example 4.23 [testcrash.go](examples/chapter_4/testcrash.go):
|
||||
示例 4.23 [testcrash.go](examples/chapter_4/testcrash.go):
|
||||
|
||||
package main
|
||||
func main() {
|
||||
var p *int = nil
|
||||
*p = 0
|
||||
}
|
||||
// in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
|
||||
// runtime error: invalid memory address or nil pointer dereference
|
||||
```go
|
||||
package main
|
||||
func main() {
|
||||
var p *int = nil
|
||||
*p = 0
|
||||
}
|
||||
// in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
|
||||
// runtime error: invalid memory address or nil pointer dereference
|
||||
```
|
||||
|
||||
**问题 4.2** 列举 Go 语言中 * 号的所有用法。
|
||||
|
||||
|
@@ -2,13 +2,13 @@
|
||||
|
||||
到目前为止,我们看到的都是 Go 程序都是从 main() 函数开始执行,然后按顺序执行该函数体中的代码。但我们经常会需要只有在满足一些特定情况时才执行某些代码,也就是说在代码里进行条件判断。针对这种需求,Go 提供了下面这些条件结构和分支结构:
|
||||
|
||||
if-else 结构
|
||||
switch 结构
|
||||
select 结构,用于 channel 的选择(第 14.4 节)
|
||||
- if-else 结构
|
||||
- switch 结构
|
||||
- elect 结构,用于 channel 的选择(第 14.4 节)
|
||||
|
||||
可以使用迭代或循环结构来重复执行一次或多次某段代码(任务):
|
||||
|
||||
for (range) 结构
|
||||
- for (range) 结构
|
||||
|
||||
一些如 `break` 和 `continue` 这样的关键字可以用于中途改变循环的状态。
|
||||
|
||||
|
172
eBook/05.1.md
172
eBook/05.1.md
@@ -2,27 +2,33 @@
|
||||
|
||||
if 是用于测试某个条件(布尔型或逻辑型)的语句,如果该条件成立,则会执行 if 后由大括号括起来的代码块,否则就忽略该代码块继续执行后续的代码。
|
||||
|
||||
if condition {
|
||||
// do something
|
||||
}
|
||||
```go
|
||||
if condition {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
如果存在第二个分支,则可以在上面代码的基础上添加 else 关键字以及另一代码块,这个代码块中的代码只有在条件不满足时才会执行。if 和 else 后的两个代码块是相互独立的分支,只可能执行其中一个。
|
||||
|
||||
if condition {
|
||||
// do something
|
||||
} else {
|
||||
// do something
|
||||
}
|
||||
```go
|
||||
if condition {
|
||||
// do something
|
||||
} else {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
如果存在第三个分支,则可以使用下面这种三个独立分支的形式:
|
||||
|
||||
if condition1 {
|
||||
// do something
|
||||
} else if condition2 {
|
||||
// do something else
|
||||
}else {
|
||||
// catch-all or default
|
||||
}
|
||||
```go
|
||||
if condition1 {
|
||||
// do something
|
||||
} else if condition2 {
|
||||
// do something else
|
||||
}else {
|
||||
// catch-all or default
|
||||
}
|
||||
```
|
||||
|
||||
else-if 分支的数量是没有限制的,但是为了代码的可读性,还是不要在 if 后面加入太多的 else-if 结构。如果你必须使用这种形式,则把尽可能先满足的条件放在前面。
|
||||
|
||||
@@ -32,10 +38,12 @@ else-if 分支的数量是没有限制的,但是为了代码的可读性,还
|
||||
|
||||
非法的Go代码:
|
||||
|
||||
if x{
|
||||
}
|
||||
else { // 无效的
|
||||
}
|
||||
```go
|
||||
if x{
|
||||
}
|
||||
else { // 无效的
|
||||
}
|
||||
```
|
||||
|
||||
要注意的是,在你使用 `gofmt` 格式化代码之后,每个分支内的代码都会缩进 4 个或 8 个空格,或者是 1 个 tab,并且右大括号与对应的 if 关键字垂直对齐。
|
||||
|
||||
@@ -43,18 +51,20 @@ else-if 分支的数量是没有限制的,但是为了代码的可读性,还
|
||||
|
||||
一种可能用到条件语句的场景是测试变量的值,在不同的情况执行不同的语句,不过将在第 5.3 节讲到的 switch 结构会更适合这种情况。
|
||||
|
||||
Example 5.1 [booleans.go](examples/chapter_5/booleans.go)
|
||||
示例 5.1 [booleans.go](examples/chapter_5/booleans.go)
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
bool1 := true
|
||||
if bool1 {
|
||||
fmt.Printf("The value is true\n")
|
||||
} else {
|
||||
fmt.Printf("The value is false\n")
|
||||
}
|
||||
```go
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
bool1 := true
|
||||
if bool1 {
|
||||
fmt.Printf("The value is true\n")
|
||||
} else {
|
||||
fmt.Printf("The value is false\n")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
@@ -66,22 +76,26 @@ Example 5.1 [booleans.go](examples/chapter_5/booleans.go)
|
||||
|
||||
当 if 结构内有 break、continue、goto 或者 return 语句时,Go 代码的常见写法是省略 else 部分(另见第 5.2 节)。无论满足哪个条件都会返回 x 或者 y 时,一般使用以下写法:
|
||||
|
||||
if condition {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
```go
|
||||
if condition {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
```
|
||||
|
||||
**注意事项** 不要同时在 if-else 结构的两个分支里都使用 return 语句,这将导致编译报错 “function ends without a return statement”(你可以认为这是一个编译器的 Bug 或者特性)。( **译者注:该问题已经在 Go 1.1 中被修复或者说改进** )
|
||||
**注意事项** 不要同时在 if-else 结构的两个分支里都使用 return 语句,这将导致编译报错 `function ends without a return statement`(你可以认为这是一个编译器的 Bug 或者特性)。( **译者注:该问题已经在 Go 1.1 中被修复或者说改进** )
|
||||
|
||||
这里举一些有用的例子:
|
||||
|
||||
1. 判断一个字符串是否为空:`if str == "" { ... }` 或 `if len(str) == 0 {...}`。
|
||||
1. 判断一个字符串是否为空:
|
||||
- `if str == "" { ... }`
|
||||
- `if len(str) == 0 {...}`
|
||||
2. 判断运行 Go 程序的操作系统类型,这可以通过常量 `runtime.GOOS` 来判断(第 2.2 节)。
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
...
|
||||
} else { // Unix - like
|
||||
...
|
||||
if runtime.GOOS == "windows" {
|
||||
. ..
|
||||
} else { // Unix - li ke
|
||||
. ..
|
||||
}
|
||||
|
||||
这段代码一般被放在 init() 函数中执行。这儿还有一段示例来演示如何根据操作系统来决定输入结束的提示:
|
||||
@@ -116,53 +130,61 @@ Example 5.1 [booleans.go](examples/chapter_5/booleans.go)
|
||||
|
||||
在第四种情况中,if 可以包含一个初始化语句(如:给一个变量赋值)。这种写法具有固定的格式(在初始化语句后方必须加上分号):
|
||||
|
||||
if initialization; condition {
|
||||
// do something
|
||||
}
|
||||
```go
|
||||
if initialization; condition {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
val := 10
|
||||
if val > max {
|
||||
// do something
|
||||
}
|
||||
```go
|
||||
val := 10
|
||||
if val > max {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
你也可以这样写:
|
||||
|
||||
if val := 10; val > max {
|
||||
// do something
|
||||
}
|
||||
```go
|
||||
if val := 10; val > max {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
但要注意的是,使用简短方式 `:=` 声明的变量的作用域只存在于 if 结构中(在 if 结构的大括号之间,如果使用 if-else 结构则在 else 代码块中变量也会存在)。如果变量在 if 结构之前就已经存在,那么在 if 结构中,该变量原来的值会被隐藏。最简单的解决方案就是不要在初始化语句中声明变量(见 5.2 节的例 3 了解更多)。
|
||||
|
||||
Example 5.2 [ifelse.go](examples/chapter_5/ifelse.go)
|
||||
示例 5.2 [ifelse.go](examples/chapter_5/ifelse.go)
|
||||
|
||||
package main
|
||||
```go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var first int = 10
|
||||
var cond int
|
||||
func main() {
|
||||
var first int = 10
|
||||
var cond int
|
||||
|
||||
if first <= 0 {
|
||||
if first <= 0 {
|
||||
|
||||
fmt.Printf("first is less than or equal to 0\n")
|
||||
} else if first > 0 && first < 5 {
|
||||
fmt.Printf("first is less than or equal to 0\n")
|
||||
} else if first > 0 && first < 5 {
|
||||
|
||||
fmt.Printf("first is between 0 and 5\n")
|
||||
} else {
|
||||
fmt.Printf("first is between 0 and 5\n")
|
||||
} else {
|
||||
|
||||
fmt.Printf("first is 5 or greater\n")
|
||||
}
|
||||
if cond = 5; cond > 10 {
|
||||
|
||||
fmt.Printf("cond is greater than 10\n")
|
||||
} else {
|
||||
|
||||
fmt.Printf("cond is not greater than 10\n")
|
||||
}
|
||||
fmt.Printf("first is 5 or greater\n")
|
||||
}
|
||||
if cond = 5; cond > 10 {
|
||||
|
||||
fmt.Printf("cond is greater than 10\n")
|
||||
} else {
|
||||
|
||||
fmt.Printf("cond is not greater than 10\n")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
@@ -170,11 +192,13 @@ Example 5.2 [ifelse.go](examples/chapter_5/ifelse.go)
|
||||
|
||||
下面的代码片段展示了如何通过在初始化语句中获取函数 `process()` 的返回值,并在条件语句中作为判定条件来决定是否执行 if 结构中的代码:
|
||||
|
||||
if value := process(data); value > max {
|
||||
...
|
||||
if value := process(data); value > max {
|
||||
...
|
||||
}
|
||||
```go
|
||||
if value := process(data); value > max {
|
||||
...
|
||||
if value := process(data); value > max {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## 链接
|
||||
|
||||
|
Reference in New Issue
Block a user