mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-11-30 06:22:32 +03:00
[go/zh-cn] Update content from English fork (#2722)
* A manual diff with latest English version * Translation for updated parts * Translate string literals
This commit is contained in:
parent
77241749f8
commit
bec5b2b879
@ -6,6 +6,7 @@ contributors:
|
|||||||
- ["Sonia Keys", "https://github.com/soniakeys"]
|
- ["Sonia Keys", "https://github.com/soniakeys"]
|
||||||
- ["pantaovay", "https://github.com/pantaovay"]
|
- ["pantaovay", "https://github.com/pantaovay"]
|
||||||
- ["lidashuang", "https://github.com/lidashuang"]
|
- ["lidashuang", "https://github.com/lidashuang"]
|
||||||
|
- ["Tim Zhang", "https://github.com/ttimasdf"]
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -27,7 +28,10 @@ package main
|
|||||||
// Import语句声明了当前文件引用的包。
|
// Import语句声明了当前文件引用的包。
|
||||||
import (
|
import (
|
||||||
"fmt" // Go语言标准库中的包
|
"fmt" // Go语言标准库中的包
|
||||||
|
"io/ioutil" // 包含一些输入输出函数
|
||||||
|
m "math" // 数学标准库,在此文件中别名为m
|
||||||
"net/http" // 一个web服务器包
|
"net/http" // 一个web服务器包
|
||||||
|
"os" // 系统底层函数,如文件读写
|
||||||
"strconv" // 字符串转换
|
"strconv" // 字符串转换
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +40,7 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
// 往标准输出打印一行。
|
// 往标准输出打印一行。
|
||||||
// 用包名fmt限制打印函数。
|
// 用包名fmt限制打印函数。
|
||||||
fmt.Println("Hello world!")
|
fmt.Println("天坑欢迎你!")
|
||||||
|
|
||||||
// 调用当前包的另一个函数。
|
// 调用当前包的另一个函数。
|
||||||
beyondHello()
|
beyondHello()
|
||||||
@ -54,7 +58,11 @@ func beyondHello() {
|
|||||||
learnTypes() // 少于y分钟,学的更多!
|
learnTypes() // 少于y分钟,学的更多!
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多变量和多返回值的函数
|
/* <- 快看快看我是跨行注释_(:з」∠)_
|
||||||
|
Go语言的函数可以有多个参数和 *多个* 返回值。
|
||||||
|
在这个函数中, `x`、`y` 是参数,
|
||||||
|
`sum`、`prod` 是返回值的标识符(可以理解为名字)且类型为int
|
||||||
|
*/
|
||||||
func learnMultiple(x, y int) (sum, prod int) {
|
func learnMultiple(x, y int) (sum, prod int) {
|
||||||
return x + y, x * y // 返回两个值
|
return x + y, x * y // 返回两个值
|
||||||
}
|
}
|
||||||
@ -62,10 +70,10 @@ func learnMultiple(x, y int) (sum, prod int) {
|
|||||||
// 内置变量类型和关键词
|
// 内置变量类型和关键词
|
||||||
func learnTypes() {
|
func learnTypes() {
|
||||||
// 短声明给你所想。
|
// 短声明给你所想。
|
||||||
s := "Learn Go!" // String类型
|
str := "少说话多读书!" // String类型
|
||||||
|
|
||||||
s2 := `A "raw" string literal
|
s2 := `这是一个
|
||||||
can include line breaks.` // 同样是String类型
|
可以换行的字符串` // 同样是String类型
|
||||||
|
|
||||||
// 非ascii字符。Go使用UTF-8编码。
|
// 非ascii字符。Go使用UTF-8编码。
|
||||||
g := 'Σ' // rune类型,int32的别名,使用UTF-8编码
|
g := 'Σ' // rune类型,int32的别名,使用UTF-8编码
|
||||||
@ -80,16 +88,29 @@ can include line breaks.` // 同样是String类型
|
|||||||
// 字符转换
|
// 字符转换
|
||||||
n := byte('\n') // byte是uint8的别名
|
n := byte('\n') // byte是uint8的别名
|
||||||
|
|
||||||
// 数组类型编译的时候大小固定。
|
// 数组(Array)类型的大小在编译时即确定
|
||||||
var a4 [4] int // 有4个int变量的数组,初始为0
|
var a4 [4] int // 有4个int变量的数组,初始为0
|
||||||
a3 := [...]int{3, 1, 5} // 有3个int变量的数组,同时进行了初始化
|
a3 := [...]int{3, 1, 5} // 有3个int变量的数组,同时进行了初始化
|
||||||
|
|
||||||
// Slice 可以动态的增删。Array和Slice各有千秋,但是使用slice的地方更多些。
|
// Array和slice各有所长,但是slice可以动态的增删,所以更多时候还是使用slice。
|
||||||
s3 := []int{4, 5, 9} // 和a3相比,这里没有省略号
|
s3 := []int{4, 5, 9} // 回去看看 a3 ,是不是这里没有省略号?
|
||||||
s4 := make([]int, 4) // 分配一个有4个int型变量的slice,全部被初始化为0
|
s4 := make([]int, 4) // 分配4个int大小的内存并初始化为0
|
||||||
|
var d2 [][]float64 // 这里只是声明,并未分配内存空间
|
||||||
|
bs := []byte("a slice") // 进行类型转换
|
||||||
|
|
||||||
var d2 [][]float64 // 声明而已,什么都没有分配
|
// 切片(Slice)的大小是动态的,它的长度可以按需增长
|
||||||
bs := []byte("a slice") // 类型转换的语法
|
// 用内置函数 append() 向切片末尾添加元素
|
||||||
|
// 要增添到的目标是 append 函数第一个参数,
|
||||||
|
// 多数时候数组在原内存处顺次增长,如
|
||||||
|
s := []int{1, 2, 3} // 这是个长度3的slice
|
||||||
|
s = append(s, 4, 5, 6) // 再加仨元素,长度变为6了
|
||||||
|
fmt.Println(s) // 更新后的数组是 [1 2 3 4 5 6]
|
||||||
|
|
||||||
|
// 除了向append()提供一组原子元素(写死在代码里的)以外,我们
|
||||||
|
// 还可以用如下方法传递一个slice常量或变量,并在后面加上省略号,
|
||||||
|
// 用以表示我们将引用一个slice、解包其中的元素并将其添加到s数组末尾。
|
||||||
|
s = append(s, []int{7, 8, 9}...) // 第二个参数是一个slice常量
|
||||||
|
fmt.Println(s) // 更新后的数组是 [1 2 3 4 5 6 7 8 9]
|
||||||
|
|
||||||
p, q := learnMemory() // 声明p,q为int型变量的指针
|
p, q := learnMemory() // 声明p,q为int型变量的指针
|
||||||
fmt.Println(*p, *q) // * 取值
|
fmt.Println(*p, *q) // * 取值
|
||||||
@ -100,13 +121,28 @@ can include line breaks.` // 同样是String类型
|
|||||||
|
|
||||||
// 在Go语言中未使用的变量在编译的时候会报错,而不是warning。
|
// 在Go语言中未使用的变量在编译的时候会报错,而不是warning。
|
||||||
// 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。
|
// 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。
|
||||||
_,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs
|
_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs
|
||||||
|
// 通常的用法是,在调用拥有多个返回值的函数时,
|
||||||
|
// 用下划线抛弃其中的一个参数。下面的例子就是一个脏套路,
|
||||||
|
// 调用os.Create并用下划线变量扔掉它的错误代码。
|
||||||
|
// 因为我们觉得这个文件一定会成功创建。
|
||||||
|
file, _ := os.Create("output.txt")
|
||||||
|
fmt.Fprint(file, "这句代码还示范了如何写入文件呢")
|
||||||
|
file.Close()
|
||||||
|
|
||||||
// 输出变量
|
// 输出变量
|
||||||
fmt.Println(s, c, a4, s3, d2, m)
|
fmt.Println(s, c, a4, s3, d2, m)
|
||||||
|
|
||||||
learnFlowControl() // 回到流程控制
|
learnFlowControl() // 回到流程控制
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 和其他编程语言不同的是,go支持有名称的变量返回值。
|
||||||
|
// 声明返回值时带上一个名字允许我们在函数内的不同位置
|
||||||
|
// 只用写return一个词就能将函数内指定名称的变量返回
|
||||||
|
func learnNamedReturns(x, y int) (z int) {
|
||||||
|
z = x * y
|
||||||
|
return // z is implicit here, because we named it earlier.
|
||||||
|
|
||||||
// Go全面支持垃圾回收。Go有指针,但是不支持指针运算。
|
// Go全面支持垃圾回收。Go有指针,但是不支持指针运算。
|
||||||
// 你会因为空指针而犯错,但是不会因为增加指针而犯错。
|
// 你会因为空指针而犯错,但是不会因为增加指针而犯错。
|
||||||
func learnMemory() (p, q *int) {
|
func learnMemory() (p, q *int) {
|
||||||
@ -126,7 +162,7 @@ func expensiveComputation() int {
|
|||||||
func learnFlowControl() {
|
func learnFlowControl() {
|
||||||
// If需要花括号,括号就免了
|
// If需要花括号,括号就免了
|
||||||
if true {
|
if true {
|
||||||
fmt.Println("told ya")
|
fmt.Println("这句话肯定被执行")
|
||||||
}
|
}
|
||||||
// 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,
|
// 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,
|
||||||
// 也不用容忍别人的代码风格。
|
// 也不用容忍别人的代码风格。
|
||||||
@ -146,7 +182,7 @@ func learnFlowControl() {
|
|||||||
}
|
}
|
||||||
// 和if一样,for也不用括号
|
// 和if一样,for也不用括号
|
||||||
for x := 0; x < 3; x++ { // ++ 自增
|
for x := 0; x < 3; x++ { // ++ 自增
|
||||||
fmt.Println("iteration", x)
|
fmt.Println("遍历", x)
|
||||||
}
|
}
|
||||||
// x在这里还是1。为什么?
|
// x在这里还是1。为什么?
|
||||||
|
|
||||||
@ -155,6 +191,19 @@ func learnFlowControl() {
|
|||||||
break // 骗你的
|
break // 骗你的
|
||||||
continue // 不会运行的
|
continue // 不会运行的
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用range可以枚举 array、slice、string、map、channel等不同类型
|
||||||
|
// 对于channel,range返回一个值,
|
||||||
|
// array、slice、string、map等其他类型返回一对儿
|
||||||
|
for key, value := range map[string]int{"one": 1, "two": 2, "three": 3} {
|
||||||
|
// 打印map中的每一个键值对
|
||||||
|
fmt.Printf("索引:%s, 值为:%d\n", key, value)
|
||||||
|
}
|
||||||
|
// 如果你只想要值,那就用前面讲的下划线扔掉没用的
|
||||||
|
for _, name := range []string{"Bob", "Bill", "Joe"} {
|
||||||
|
fmt.Printf("你是。。 %s\n", name)
|
||||||
|
}
|
||||||
|
|
||||||
// 和for一样,if中的:=先给y赋值,然后再和x作比较。
|
// 和for一样,if中的:=先给y赋值,然后再和x作比较。
|
||||||
if y := expensiveComputation(); y > x {
|
if y := expensiveComputation(); y > x {
|
||||||
x = y
|
x = y
|
||||||
@ -167,13 +216,51 @@ func learnFlowControl() {
|
|||||||
x /= 1e5 // x变成10
|
x /= 1e5 // x变成10
|
||||||
fmt.Println("xBig:", xBig()) // 现在是false
|
fmt.Println("xBig:", xBig()) // 现在是false
|
||||||
|
|
||||||
|
// 除此之外,函数体可以在其他函数中定义并调用,
|
||||||
|
// 满足下列条件时,也可以作为参数传递给其他函数:
|
||||||
|
// a) 定义的函数被立即调用
|
||||||
|
// b) 函数返回值符合调用者对类型的要求
|
||||||
|
fmt.Println("两数相加乘二: ",
|
||||||
|
func(a, b int) int {
|
||||||
|
return (a + b) * 2
|
||||||
|
}(10, 2)) // Called with args 10 and 2
|
||||||
|
// => Add + double two numbers: 24
|
||||||
|
|
||||||
// 当你需要goto的时候,你会爱死它的!
|
// 当你需要goto的时候,你会爱死它的!
|
||||||
goto love
|
goto love
|
||||||
love:
|
love:
|
||||||
|
|
||||||
|
learnFunctionFactory() // 返回函数的函数多棒啊
|
||||||
|
learnDefer() // 对defer关键字的简单介绍
|
||||||
learnInterfaces() // 好东西来了!
|
learnInterfaces() // 好东西来了!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func learnFunctionFactory() {
|
||||||
|
// 空行分割的两个写法是相同的,不过第二个写法比较实用
|
||||||
|
fmt.Println(sentenceFactory("原谅")("当然选择", "她!"))
|
||||||
|
|
||||||
|
d := sentenceFactory("原谅")
|
||||||
|
fmt.Println(d("当然选择", "她!"))
|
||||||
|
fmt.Println(d("你怎么可以", "她?"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator在一些语言中很常见,在go语言中,
|
||||||
|
// 接受参数作为其定义的一部分的函数是修饰符的替代品
|
||||||
|
func sentenceFactory(mystring string) func(before, after string) string {
|
||||||
|
return func(before, after string) string {
|
||||||
|
return fmt.Sprintf("%s %s %s", before, mystring, after) // new string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func learnDefer() (ok bool) {
|
||||||
|
// defer表达式在函数返回的前一刻执行
|
||||||
|
defer fmt.Println("defer表达式执行顺序为后进先出(LIFO)")
|
||||||
|
defer fmt.Println("\n这句话比上句话先输出,因为")
|
||||||
|
// 关于defer的用法,例如用defer关闭一个文件,
|
||||||
|
// 就可以让关闭操作与打开操作的代码更近一些
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 定义Stringer为一个接口类型,有一个方法String
|
// 定义Stringer为一个接口类型,有一个方法String
|
||||||
type Stringer interface {
|
type Stringer interface {
|
||||||
String() string
|
String() string
|
||||||
@ -205,6 +292,20 @@ func learnInterfaces() {
|
|||||||
fmt.Println(p) // 输出和上面一样,自动调用String函数。
|
fmt.Println(p) // 输出和上面一样,自动调用String函数。
|
||||||
fmt.Println(i) // 输出和上面一样。
|
fmt.Println(i) // 输出和上面一样。
|
||||||
|
|
||||||
|
learnVariadicParams("great", "learning", "here!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有变长参数列表的函数
|
||||||
|
func learnVariadicParams(myStrings ...interface{}) {
|
||||||
|
// 枚举变长参数列表的每个参数值
|
||||||
|
// 下划线在这里用来抛弃枚举时返回的数组索引值
|
||||||
|
for _, param := range myStrings {
|
||||||
|
fmt.Println("param:", param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将可变参数列表作为其他函数的参数列表
|
||||||
|
fmt.Println("params:", fmt.Sprintln(myStrings...))
|
||||||
|
|
||||||
learnErrorHandling()
|
learnErrorHandling()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +313,7 @@ func learnErrorHandling() {
|
|||||||
// ", ok"用来判断有没有正常工作
|
// ", ok"用来判断有没有正常工作
|
||||||
m := map[int]string{3: "three", 4: "four"}
|
m := map[int]string{3: "three", 4: "four"}
|
||||||
if x, ok := m[1]; !ok { // ok 为false,因为m中没有1
|
if x, ok := m[1]; !ok { // ok 为false,因为m中没有1
|
||||||
fmt.Println("no one there")
|
fmt.Println("别找了真没有")
|
||||||
} else {
|
} else {
|
||||||
fmt.Print(x) // 如果x在map中的话,x就是那个值喽。
|
fmt.Print(x) // 如果x在map中的话,x就是那个值喽。
|
||||||
}
|
}
|
||||||
@ -251,11 +352,11 @@ func learnConcurrency() {
|
|||||||
// 它随机选择一个准备好通讯的case。
|
// 它随机选择一个准备好通讯的case。
|
||||||
select {
|
select {
|
||||||
case i := <-c: // 从channel接收的值可以赋给其他变量
|
case i := <-c: // 从channel接收的值可以赋给其他变量
|
||||||
fmt.Println("it's a", i)
|
fmt.Println("这是……", i)
|
||||||
case <-cs: // 或者直接丢弃
|
case <-cs: // 或者直接丢弃
|
||||||
fmt.Println("it's a string")
|
fmt.Println("这是个字符串!")
|
||||||
case <-cc: // 空的,还没作好通讯的准备
|
case <-cc: // 空的,还没作好通讯的准备
|
||||||
fmt.Println("didn't happen.")
|
fmt.Println("别瞎想")
|
||||||
}
|
}
|
||||||
// 上面c或者cs的值被取到,其中一个goroutine结束,另外一个一直阻塞。
|
// 上面c或者cs的值被取到,其中一个goroutine结束,另外一个一直阻塞。
|
||||||
|
|
||||||
@ -265,22 +366,43 @@ func learnConcurrency() {
|
|||||||
// http包中的一个简单的函数就可以开启web服务器。
|
// http包中的一个简单的函数就可以开启web服务器。
|
||||||
func learnWebProgramming() {
|
func learnWebProgramming() {
|
||||||
// ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。
|
// ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。
|
||||||
err := http.ListenAndServe(":8080", pair{})
|
go func() {
|
||||||
fmt.Println(err) // 不要无视错误。
|
err := http.ListenAndServe(":8080", pair{})
|
||||||
|
fmt.Println(err) // 不要无视错误。
|
||||||
|
}()
|
||||||
|
|
||||||
|
requestServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使pair实现http.Handler接口的ServeHTTP方法。
|
// 使pair实现http.Handler接口的ServeHTTP方法。
|
||||||
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// 使用http.ResponseWriter返回数据
|
// 使用http.ResponseWriter返回数据
|
||||||
w.Write([]byte("You learned Go in Y minutes!"))
|
w.Write([]byte("Y分钟golang速成!"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestServer() {
|
||||||
|
resp, err := http.Get("http://localhost:8080")
|
||||||
|
fmt.Println(err)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
fmt.Printf("\n服务器消息: `%s`", string(body))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 更进一步
|
## 更进一步
|
||||||
|
|
||||||
Go的根源在[Go官方网站](http://golang.org/)。
|
关于Go的一切你都可以在[Go官方网站](http://golang.org/)找到。
|
||||||
在那里你可以学习入门教程,通过浏览器交互式地学习,而且可以读到很多东西。
|
在那里你可以获得教程参考,在线试用,和更多的资料。
|
||||||
|
在简单的尝试过后,在[官方文档](https://golang.org/doc/)那里你会得到你所需要的所有资料、关于编写代码的规范、库和命令行工具的文档与Go的版本历史。
|
||||||
|
|
||||||
强烈推荐阅读语言定义部分,很简单而且很简洁!(as language definitions go these days.)
|
强烈推荐阅读语言定义部分,很简单而且很简洁!(赶时髦!)
|
||||||
|
|
||||||
|
你还可以前往[Go在线体验中心](https://play.golang.org/p/tnWMjr16Mm)进,在浏览器里修改并运行这些代码,一定要试一试哦!你可以将[https://play.golang.org](https://play.golang.org)当作一个[REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop),在那里体验语言特性或运行自己的代码,连环境都不用配!
|
||||||
|
|
||||||
学习Go还要阅读Go[标准库的源代码](http://golang.org/src/),全部文档化了,可读性非常好,可以学到go,go style和go idioms。在[文档](http://golang.org/pkg/)中点击函数名,源代码就出来了!
|
学习Go还要阅读Go[标准库的源代码](http://golang.org/src/),全部文档化了,可读性非常好,可以学到go,go style和go idioms。在[文档](http://golang.org/pkg/)中点击函数名,源代码就出来了!
|
||||||
|
|
||||||
|
[Go by example](https://gobyexample.com/)也是一个学习的好地方。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Go Mobile添加了对移动平台的支持(Android and iOS)。你可以完全用go语言来创造一个app或编写一个可以从Java或Obj-C调用的函数库,敬请参考[Go Mobile page](https://github.com/golang/go/wiki/Mobile)。
|
||||||
|
Loading…
Reference in New Issue
Block a user