1. Tutorial
1.1 Hello,world
Go 代码被归入 package 中进行组织,package 类似于其他语言的 libraries 或者 modules。一个 package 由一个或多个 在同一目录下的 .go 源文件组成,它们定义了包做了什么。每个源文件都以一个 package 声明开头,这声明了文件属于哪个包,紧接着是它导入的其他包的列表,然后程序的声明被存储到文件中。
Package main 是特殊的,它定义了一个单独的可执行程序,不是一个库。在 package main 中,函数 main 也是特殊的,它是函数执行的起始点。main 所做的即是程序所做的。
我们必须告诉编译器这个源文件需要哪些包。这就是紧跟着 package 声明的 import 声明的工作。
你必须明确的导入你所需要的包。如果有忘记导入的或者不必要导入的 package,一个程序不会被编译。
import 声明必须跟随着包的声明。在那之后,程序由函数,变量,常量,和类型(由关键词 func,var,const,type)的声明组成。对于大部分情况,声明的顺序并不重要。
函数声明由关键词 func,函数名,参数列表,结果列表,和函数体 – 由花括号封闭。
Go 在语句或者声明之后不需要分号,除非在相同的一行中出现多个。实际上,跟随特定 tokens 的新行被转化为分号,所以新的一行放在什么地方与 Go 代码的合适解析关系重大。比如,函数的打开的 { 必须与函数声明的末尾在同一行,不能自己另开一行,在 x + y 的表达式中,新起一行在 + 号之后是允许的,但是不能在 + 号之前。
1.2 Command-Line Arguments
os package 提供函数和其他值来以平台无关的风格处理操作系统。Command-line 参数被存储在名为 Args 的变量中,Args 是 os package 的一部分。因此,os package 之外它的名字是 os.Args。
变量 os.Args 是字符串的 slice。Slices 是 Go 中的基本概念,目前,我们可以将 slice 视为一个动态大小的数组元素的序列 s,单独的元素可以由 s[i] 访问,连续的序列可以由 s[m:n] 访问。元素的数量由 len(s) 给出。正如大部分的其他的编程语言,Go 中所有的索引都使用半开区间,它包含第一个 index,但是不包含最后一个。
os.Args 的第一个元素,os.Args[0],是命令行自己的名字;其他的参数是在程序开始执行时呈现给 program 参数。一个格式为 s[m:n] 的 slice 表达式产生一个 slice,它引用从 m 到 n-1 的元素。如果 m 或者 n 是缺省的,它的默认值为 0 或者 len(s)。所以我们可以缩写期望的 slice 为 os.Args[1:]。
// Echo1 prints its command-line arguments.
package main
import(
"fmt"
"os"
)
func main() {
var s, sep string
for i := 1;i < len(os.Args); i++ {
s += os.Args[i] + sep
sep = " "
}
fmt.Println(s);
}
- 注释以 // 开始。从 // 开始到本行结束的所有文本都是注释。
- := 符号是 short variable declaration 的一部分,short variable declaration 声明一个或多个变量并基于初始化器的值给予它们合适的类型。
- Go 中唯一的循环语句是 for 循环。
// Echo2 prints its command-line arguments.
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for(_, arg := range os.Args[1:]) {
s += arg + sep
sep = " "
}
fmt.Println(s)
}
- range 用于遍历某些数据类型,比如 slice,string 中的值,每次返回两个值,index 和 value。
- blank identifier _用于表示在语法上需要但是逻辑上不需要的变量,比如上述循环中的 index。(Go 不允许未被使用的局部变量存在)
package main
import(
"fmt"
"os"
"string"
)
func main() {
fmt.Println(strings.Join(os.Args[1:], ""))
}
package
import(
"fmt"
"os"
)
func main() {
fmt.Println(os.Args[1:])
}
1.3 Finding Duplicate Lines
// Dup1 prints the text of each line that appears more than
// once in the standard input, preceded by its count.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
- map 存储一系列的键值对并提供常数时间的操作来存储,检索,或测试集合中的元素。键可以为任意类型,只要其值能够使用 == 进行比较。
- map 迭代的顺序并不是特定的,实际上,它是随机的,每一次运行都会变化。
// Dup2 prints the count and text of lines that appear more than once
// in the input. It reads from stdin or from a list of named files.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]())
files := os.Args[1:]
if len(files) == 0 {
countLines(os.Stdin(), counts)
}
else {
for _, file := range files {
f, err := os.Open(file)
if err != nil {
rmt.FPrinf(os.Stderr, "dup2: %v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
func countLines(f *os.File, counts map[string]int) {
input := bufio.NewScanner()
for input.Scan() {
counts[input.Text()]++;
}
}
- make 创建的数据结构 map 是一个引用。
package main
import(
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
counts := make(map[string]int)
for _, filename := range os.Args[1:] {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.FPrintf(os.Stderr, "dup3: %v\n", err)
continue
}
for _, line = range strings.Split(string(data), "\n") {
counts[line]++
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}