mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 22:06:51 +08:00
@@ -1,6 +1,6 @@
|
||||
# 9.1 标准库概述
|
||||
|
||||
像 fmt,os 等这样具有常用功能的内置包在 Go 语言中有 150 个以上,它们被称为标准库,大部分(一些底层的除外)内置于 Go 本身。记录在: http://golang.org/pkg/。
|
||||
像 fmt,os 等这样具有常用功能的内置包在 Go 语言中有 150 个以上,它们被称为标准库,大部分(一些底层的除外)内置于 Go 本身。记录在: [http://golang.org/pkg/](http://golang.org/pkg/)。
|
||||
|
||||
在贯穿本书的例子和练习中,我们都是用标准库的包。可以通过查阅第 350 页包中的内容快速找到相关的包的实例。这里我们只是按功能进行分组来介绍这些包的简单用途,我们不会深入讨论他们的内部结构。
|
||||
|
||||
@@ -81,11 +81,11 @@ for e := l.Front(); e != nil; e = e.Next() {
|
||||
|
||||
exp 包中有许多将被编译为新包的实验性的包。它们将成为独立的包在下次稳定版本发布的时候。如果前一个版本已经存在了,它们将被作为果实的包被回收。然而Go1.0发布的时候并不包含过时或者实验性的包。
|
||||
|
||||
** 练习9.1 **
|
||||
**练习9.1**
|
||||
|
||||
使用 container/list 包实现一个双向链表,将 101,102,103 放入其中并打印出来。
|
||||
|
||||
**练习9.2 **
|
||||
**练习9.2**
|
||||
|
||||
通过使用 unsafe 包中的方法来测试你电脑上一个整型变量占用多少个字节。
|
||||
|
||||
|
BIN
eBook/09.10.md
BIN
eBook/09.10.md
Binary file not shown.
@@ -24,8 +24,11 @@ func ReturnStr() string {
|
||||
|
||||
```go
|
||||
import “./pack1/pack1”
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
import 的一般格式如下:
|
||||
|
||||
import “包的路径或url地址“ 像 import "github.com/org1/pack1”
|
||||
|
||||
路径是指当前目录的相对路径。
|
||||
|
||||
@@ -43,31 +46,37 @@ func main() {
|
||||
var test1 string
|
||||
test1 = pack1.ReturnStr()
|
||||
fmt.Printf("ReturnStr from package1: %s\n", test1)
|
||||
var test1 string
|
||||
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
||||
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
||||
}
|
||||
```
|
||||
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
||||
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
||||
|
||||
输出结果:
|
||||
|
||||
ReturnStr from package1: Hello main!
|
||||
Integer from package1: 42
|
||||
|
||||
如果包 pack1 和我们的程序在统同一路径下,我们可以通过 `"import ./pack1"` 这样的方式来引入,但这不被视为一个好的方法。
|
||||
|
||||
输出结果:
|
||||
|
||||
`fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)` 这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误:
|
||||
|
||||
cannot refer to unexported name pack1.pack1Float
|
||||
|
||||
主程序利用的包必须在主程序编写之前被编译。主程序中每个 pack1 项目都要通过包名来使用使用:pack1.Item。具体使用方法请参见示例 4.6 和 4.7。
|
||||
|
||||
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的 go 文件)都存放在和包名相同的子目录下:
|
||||
|
||||
|
||||
**Import with .** : import . “./pack1”
|
||||
|
||||
当使用.来做为包的别名时,你可以不通过包名来使用其中的项目。例如:`test := ReturnStr()`。
|
||||
|
||||
在当前的命名空间导入 pack1 包,一般是为了具有更好的测试效果。
|
||||
|
||||
|
||||
**Import with _** : import _ “./pack1/pack1”
|
||||
|
||||
|
||||
pack1包只导入其副作用,也就是说,只执行它的init函数并初始化其中的全局变量。
|
||||
|
||||
|
||||
**导入外部安装包:**
|
||||
|
||||
如果你要在你的应用中使用一个或多个外部包,首先你必须使用 go install(参见第 9.7 节)在你的本地机器上安装它们。
|
||||
|
||||
@@ -83,11 +92,11 @@ pack1包只导入其副作用,只执行了它的init函数并初始化了其
|
||||
|
||||
import goex “codesite.ext/author/goExample/goex”
|
||||
|
||||
|
||||
因此该包的URL将用作导入路径。
|
||||
|
||||
在 http://golang.org/cmd/goinstall/ 的 go install 文档中列出了一些广泛被使用的托管在网络代码仓库的包的导入路径
|
||||
|
||||
|
||||
**包的初始化:**
|
||||
|
||||
程序的执行开始于导入包,初始化 main 包然后调用 main 函数。
|
||||
|
||||
@@ -97,24 +106,34 @@ init 函数是不能被调用的。
|
||||
|
||||
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次。
|
||||
|
||||
|
||||
**编译并安装一个包(参见第 9.7 节):**
|
||||
|
||||
|
||||
在 Linux/OS X 下可以用类似第 4.3 节的 Makefile 脚本做到这一点:
|
||||
|
||||
|
||||
init 函数是不能被调用的。
|
||||
include $(GOROOT)/src/Make.inc
|
||||
TARG=pack1
|
||||
GOFILES=\
|
||||
pack1.go\
|
||||
pack1b.go\
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
|
||||
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次。
|
||||
确保的它可执行性通过 `chmod 777 ./Makefile`。
|
||||
|
||||
编译并安装一个包(参见第 9.7 节):
|
||||
上面脚本内的include语引入了相应的功能,将自动检测机器的架构并调用正确的编译器和链接器。
|
||||
|
||||
然后终端执行 make 或 `gomake` 工具:他们都会生成一个包含静态库 pack1.a 的 _obj 目录。
|
||||
|
||||
go install(参见第 9.7 节,从 Go1 的首选方式)同样复制 pack1.a 到本地的 $GOROOT/pkg 的目录中一个以操作系统为名的子目录下。像 import "pack1" 代替 import "path to pack1",这样只通过名字就可以将包在程序中导入。
|
||||
|
||||
如果不可取或不被允许,通过 6/8g 使用 -I 选项来编译:
|
||||
|
||||
GOFILES=\
|
||||
pack1.go\
|
||||
pack1b.go\
|
||||
6g—I map_pack1 package_test.go # where map_pack1 is the map which contains pack1.a
|
||||
|
||||
(I 选项让编译器查找选项后的目录下是否包含这个包)
|
||||
|
||||
使用 6/8l 的 -L 选项链接:
|
||||
|
||||
6l—L map_pack1 package_test.6
|
||||
|
||||
当第 13 章我们遇到使用测试工具进行测试的时候我们将重新回到自己的包的制作和编译这个话题。
|
||||
|
||||
@@ -133,9 +152,9 @@ go install(参见第 9.7 节,从 Go1 的首选方式)同样复制 pack1.a 到
|
||||
|
||||
使用 main_greetings 作出合适的问候(提示:使用 time 包)。
|
||||
|
||||
6l—L map_pack1 package_test.6
|
||||
练习 9.4:创建一个程序 main_oddven.go 判断前 100 个整数是不是偶数,包内同时包含测试的功能。
|
||||
|
||||
当第 13 章我们遇到使用测试工具进行测试的时候我们将重新回到自己的包的制作和编译这个话题。
|
||||
练习 9.5:使用第 6.6 节的斐波那契程序:
|
||||
|
||||
(1)将斐波那契功能放入自己的 fibo 包中并通过主程序调用它,存储最后输入的值在函数的全局变量。
|
||||
|
||||
|
@@ -4,7 +4,7 @@ go install 是 Go 中自动包安装工具:如需要将包安装到本地它
|
||||
|
||||
在包安装前的先决条件是要自动处理包自身依赖关系的安装。被依赖的包也会安装到子目录下,但是没有文档和示例:可以到网上浏览。
|
||||
|
||||
被安装包的列表可以在 $GORROT/goinstall.log 找到。
|
||||
被安装包的列表可以在 $GOROOT/goinstall.log 找到。
|
||||
|
||||
go install 使用了 GOPATH 变量(详见第 2.2 节)。
|
||||
|
||||
|
9
eBook/12.0.md
Normal file
9
eBook/12.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 读写数据
|
||||
|
||||
除了 fmt 和 os 包,我们还需要用到 bufio 包来处理缓冲的输入和输出。
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一章:[接口(interface)与反射(reflection)](11.0.md)
|
||||
- 下一节:[读取用户的输入](12.1.md)
|
151
eBook/12.1.md
Normal file
151
eBook/12.1.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# 读取用户的输入
|
||||
|
||||
我们如何读取用户的键盘(控制台)输入呢?从键盘和标准输入 `os.Stdin` 读取输入,最简单的办法是使用 `fmt` 包提供的 Scan 和 Sscan 开头的函数。请看以下程序:
|
||||
|
||||
**Listing 12.1—readinput1.go:**
|
||||
|
||||
```go
|
||||
// 从控制台读取输入:
|
||||
package main
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
firstName, lastName, s string
|
||||
i int
|
||||
f float32
|
||||
input = "56.12 / 5212 / Go"
|
||||
format = "%f / %d / %s"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Please enter your full name: ")
|
||||
fmt.Scanln(&firstName, &lastName)
|
||||
// fmt.Scanf("%s %s", &firstName, &lastName)
|
||||
fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels
|
||||
fmt.Sscanf(input, format, &f, &i, &s)
|
||||
fmt.Println("From the string we read: ", f, i, s)
|
||||
// 输出结果: From the string we read: 56.12 5212 Go
|
||||
}
|
||||
```
|
||||
|
||||
`Scanln` 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。`Scanf` 与其类似,除了 `Scanf` 的第一个参数用作格式字符串,用来决定如何读取。`Sscan` 和以 `Sscan` 开头的函数则是从字符串读取,除此之外,与 `Scanf` 相同。如果这些函数读取到的结果与您预想的不同,您可以检查成功读入数据的个数和返回的错误。
|
||||
|
||||
您也可以使用 `bufio` 包提供的缓冲读取(buffered reader)来读取数据,正如以下例子所示:
|
||||
|
||||
**Listing 12.2—readinput2.go:**
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"bufio"
|
||||
"os"
|
||||
)
|
||||
|
||||
var inputReader *bufio.Reader
|
||||
var input string
|
||||
var err error
|
||||
|
||||
func main() {
|
||||
inputReader = bufio.NewReader(os.Stdin)
|
||||
fmt.Println("Please enter some input: ")
|
||||
input, err = inputReader.ReadString('\n')
|
||||
if err == nil {
|
||||
fmt.Printf("The input was: %s\n", input)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`inputReader` 是一个指向 `bufio.Reader` 的指针。`inputReader := bufio.NewReader(os.Stdin)` 这行代码,将会创建一个读取器,并将其与标准输入绑定。
|
||||
|
||||
`bufio.NewReader()` 构造函数的签名为:`func NewReader(rd io.Reader) *Reader`
|
||||
|
||||
该函数的实参可以是满足 `io.Reader` 接口的任意对象(任意包含有适当的 `Read()` 方法的对象,请参考[章节11.8](11.8.md)),函数返回一个新的带缓冲的 `io.Reader` 对象,它将从指定读取器(例如 `os.Stdin`)读取内容。
|
||||
|
||||
返回的读取器对象提供一个方法 `ReadString(delim byte)`,该方法从输入中读取内容,直到碰到 `delim` 指定的字符,然后将读取到的内容连同 `delim` 字符一起放到缓冲区。
|
||||
|
||||
`ReadString` 返回读取到的字符串,如果碰到错误则返回 `nil`。如果它一直读到文件结束,则返回读取到的字符串和 `io.EOF`。如果读取过程中没有碰到 `delim` 字符,将返回错误 `err != nil`。
|
||||
|
||||
在上面的例子中,我们会读取键盘输入,直到回车键(\n)被按下。
|
||||
|
||||
屏幕是标准输出 `os.Stdout`;`os.Stderr` 用于显示错误信息,大多数情况下等同于 `os.Stdout`。
|
||||
|
||||
一般情况下,我们会省略变量声明,而使用 `:=`,例如:
|
||||
```go
|
||||
inputReader := bufio.NewReader(os.Stdin)
|
||||
input, err := inputReader.ReadString('\n')
|
||||
```
|
||||
|
||||
我们将从现在开始使用这种写法。
|
||||
|
||||
第二个例子从键盘读取输入,使用了 `switch` 语句:
|
||||
|
||||
**Listing 12.3—switch_input.go:**
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"bufio"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inputReader := bufio.NewReader(os.Stdin)
|
||||
fmt.Println("Please enter your name:")
|
||||
input, err := inputReader.ReadString('\n')
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("There were errors reading, exiting program.")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Your name is %s", input)
|
||||
// For Unix: test with delimiter "\n", for Windows: test with "\r\n"
|
||||
switch input {
|
||||
case "Philip\r\n": fmt.Println("Welcome Philip!")
|
||||
case "Chris\r\n": fmt.Println("Welcome Chris!")
|
||||
case "Ivo\r\n": fmt.Println("Welcome Ivo!")
|
||||
default: fmt.Printf("You are not welcome here! Goodbye!")
|
||||
}
|
||||
|
||||
// version 2:
|
||||
switch input {
|
||||
case "Philip\r\n": fallthrough
|
||||
case "Ivo\r\n": fallthrough
|
||||
case "Chris\r\n": fmt.Printf("Welcome %s\n", input)
|
||||
default: fmt.Printf("You are not welcome here! Goodbye!\n")
|
||||
}
|
||||
|
||||
// version 3:
|
||||
switch input {
|
||||
case "Philip\r\n", "Ivo\r\n": fmt.Printf("Welcome %s\n", input)
|
||||
default: fmt.Printf("You are not welcome here! Goodbye!\n")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
注意:Unix和Windows的行结束符是不同的!
|
||||
|
||||
**练习**
|
||||
|
||||
**Exercise 12.1:** word_letter_count.go
|
||||
Write a program which reads text from the keybord. When the user enters ‘S’ in order to signal the end of the input, the program shows 3 numbers:
|
||||
i) the number of characters including spaces (but excluding ‘\r’ and ‘\n’)
|
||||
ii) the number of words
|
||||
iii) the number of lines
|
||||
|
||||
**Exercise 12.2:** calculator.go
|
||||
Make a simple (reverse polish notation) calculator. This program accepts input from the user in the
|
||||
form of integers (maximum 999999) and operators (+, -, *, /).
|
||||
|
||||
The input is like this: number1 ENTER number2 ENTER operator ENTER result is displayed.
|
||||
|
||||
The programs stops if the user inputs “q”. Use the package stack you developed in Ex. 11.3
|
||||
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[读写数据](12.0.md)
|
||||
- 下一节:[文件读写](12.2.md)
|
@@ -89,7 +89,7 @@
|
||||
|
||||
## 第三部分:Go 高级编程
|
||||
|
||||
- 第12章:读写数据
|
||||
- 第12章:[读写数据](12.0.md)
|
||||
- 第13章:错误处理与测试
|
||||
- 第14章:goroutine 与 channel
|
||||
- 第15章:网络、模版与网页应用
|
||||
|
14
eBook/examples/chapter_9/book/package_test.go
Normal file
14
eBook/examples/chapter_9/book/package_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"./pack1/pack1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var test1 string
|
||||
test1 = pack1.ReturnStr()
|
||||
fmt.Printf("ReturnStr from package1: %s\n", test1)
|
||||
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
|
||||
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
|
||||
}
|
Reference in New Issue
Block a user