diff options
| -rw-r--r-- | zh-cn/go-cn.html.markdown | 194 | 
1 files changed, 158 insertions, 36 deletions
| diff --git a/zh-cn/go-cn.html.markdown b/zh-cn/go-cn.html.markdown index fa4540a2..75498367 100644 --- a/zh-cn/go-cn.html.markdown +++ b/zh-cn/go-cn.html.markdown @@ -6,7 +6,8 @@ contributors:      - ["Sonia Keys", "https://github.com/soniakeys"]      - ["pantaovay", "https://github.com/pantaovay"]      - ["lidashuang", "https://github.com/lidashuang"] -     +    - ["Tim Zhang", "https://github.com/ttimasdf"] +  ---  发明Go语言是出于更好地完成工作的需要。Go不是计算机科学的最新发展潮流,但它却提供了解决现实问题的最新最快的方法。 @@ -27,7 +28,10 @@ package main  // Import语句声明了当前文件引用的包。  import (      "fmt"       // Go语言标准库中的包 +    "io/ioutil" // 包含一些输入输出函数 +    m "math"    // 数学标准库,在此文件中别名为m      "net/http"  // 一个web服务器包 +    "os"        // 系统底层函数,如文件读写      "strconv"   // 字符串转换  ) @@ -36,7 +40,7 @@ import (  func main() {      // 往标准输出打印一行。      // 用包名fmt限制打印函数。 -    fmt.Println("Hello world!") +    fmt.Println("天坑欢迎你!")      // 调用当前包的另一个函数。      beyondHello() @@ -54,7 +58,11 @@ func beyondHello() {      learnTypes()                            // 少于y分钟,学的更多!  } -// 多变量和多返回值的函数 +/* <- 快看快看我是跨行注释_(:з」∠)_ +Go语言的函数可以有多个参数和 *多个* 返回值。 +在这个函数中, `x`、`y` 是参数, +`sum`、`prod` 是返回值的标识符(可以理解为名字)且类型为int +*/  func learnMultiple(x, y int) (sum, prod int) {      return x + y, x * y // 返回两个值  } @@ -62,11 +70,11 @@ func learnMultiple(x, y int) (sum, prod int) {  // 内置变量类型和关键词  func learnTypes() {      // 短声明给你所想。 -    s := "Learn Go!" // String类型 +    str := "少说话多读书!" // String类型 + +    s2 := `这是一个 +可以换行的字符串` // 同样是String类型 -    s2 := `A "raw" string literal -can include line breaks.` // 同样是String类型 -          // 非ascii字符。Go使用UTF-8编码。      g := 'Σ' // rune类型,int32的别名,使用UTF-8编码 @@ -80,16 +88,29 @@ can include line breaks.` // 同样是String类型      // 字符转换      n := byte('\n') // byte是uint8的别名 -    // 数组类型编译的时候大小固定。 +    // 数组(Array)类型的大小在编译时即确定      var a4 [4] int              // 有4个int变量的数组,初始为0      a3 := [...]int{3, 1, 5}     // 有3个int变量的数组,同时进行了初始化 -    // Slice 可以动态的增删。Array和Slice各有千秋,但是使用slice的地方更多些。 -    s3 := []int{4, 5, 9}        // 和a3相比,这里没有省略号 -    s4 := make([]int, 4)        // 分配一个有4个int型变量的slice,全部被初始化为0 - -    var d2 [][]float64          // 声明而已,什么都没有分配 -    bs := []byte("a slice")     // 类型转换的语法 +    // Array和slice各有所长,但是slice可以动态的增删,所以更多时候还是使用slice。 +    s3 := []int{4, 5, 9}    // 回去看看 a3 ,是不是这里没有省略号? +    s4 := make([]int, 4)    // 分配4个int大小的内存并初始化为0 +    var d2 [][]float64      // 这里只是声明,并未分配内存空间 +    bs := []byte("a slice") // 进行类型转换 + +    // 切片(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型变量的指针      fmt.Println(*p, *q)         // * 取值 @@ -100,13 +121,28 @@ can include line breaks.` // 同样是String类型      // 在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) -    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有指针,但是不支持指针运算。  // 你会因为空指针而犯错,但是不会因为增加指针而犯错。  func learnMemory() (p, q *int) { @@ -126,7 +162,7 @@ func expensiveComputation() int {  func learnFlowControl() {      // If需要花括号,括号就免了      if true { -        fmt.Println("told ya") +        fmt.Println("这句话肯定被执行")      }      // 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,      // 也不用容忍别人的代码风格。 @@ -146,15 +182,28 @@ func learnFlowControl() {      }      // 和if一样,for也不用括号      for x := 0; x < 3; x++ { // ++ 自增 -        fmt.Println("iteration", x) +        fmt.Println("遍历", x)      }      // x在这里还是1。为什么?      // for 是go里唯一的循环关键字,不过它有很多变种      for { // 死循环 -        break    // 骗你的  +        break    // 骗你的          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作比较。      if y := expensiveComputation(); y > x {          x = y @@ -163,17 +212,55 @@ func learnFlowControl() {      xBig := func() bool {          return x > 100 // x是上面声明的变量引用      } -    fmt.Println("xBig:", xBig()) // true (上面把y赋给x了)  +    fmt.Println("xBig:", xBig()) // true (上面把y赋给x了)      x /= 1e5                     // x变成10      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 love  love: +    learnFunctionFactory() // 返回函数的函数多棒啊 +    learnDefer()      // 对defer关键字的简单介绍      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  type Stringer interface {      String() string @@ -194,9 +281,9 @@ func (p pair) String() string { // p被叫做“接收器”  func learnInterfaces() {      // 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。      p := pair{3, 4} -    fmt.Println(p.String()) // 调用pair类型p的String方法  -    var i Stringer          // 声明i为Stringer接口类型  -    i = p                   // 有效!因为p实现了Stringer接口(类似java中的塑型)  +    fmt.Println(p.String()) // 调用pair类型p的String方法 +    var i Stringer          // 声明i为Stringer接口类型 +    i = p                   // 有效!因为p实现了Stringer接口(类似java中的塑型)      // 调用i的String方法,输出和上面一样      fmt.Println(i.String()) @@ -205,14 +292,28 @@ func learnInterfaces() {      fmt.Println(p) // 输出和上面一样,自动调用String函数。      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()  }  func learnErrorHandling() { -    // ", ok"用来判断有没有正常工作  +    // ", ok"用来判断有没有正常工作      m := map[int]string{3: "three", 4: "four"}      if x, ok := m[1]; !ok { // ok 为false,因为m中没有1 -        fmt.Println("no one there") +        fmt.Println("别找了真没有")      } else {          fmt.Print(x) // 如果x在map中的话,x就是那个值喽。      } @@ -245,17 +346,17 @@ func learnConcurrency() {      cs := make(chan string)       // 操作string的channel      cc := make(chan chan string)  // 操作channel的channel -    go func() { c <- 84 }()       // 开始一个goroutine来发送一个新的数字  +    go func() { c <- 84 }()       // 开始一个goroutine来发送一个新的数字      go func() { cs <- "wordy" }() // 发送给cs      // Select类似于switch,但是每个case包括一个channel操作。      // 它随机选择一个准备好通讯的case。      select {      case i := <-c: // 从channel接收的值可以赋给其他变量 -        fmt.Println("it's a", i) +        fmt.Println("这是……", i)      case <-cs: // 或者直接丢弃 -        fmt.Println("it's a string") -    case <-cc: // 空的,还没作好通讯的准备  -        fmt.Println("didn't happen.") +        fmt.Println("这是个字符串!") +    case <-cc: // 空的,还没作好通讯的准备 +        fmt.Println("别瞎想")      }      // 上面c或者cs的值被取到,其中一个goroutine结束,另外一个一直阻塞。 @@ -265,22 +366,43 @@ func learnConcurrency() {  // http包中的一个简单的函数就可以开启web服务器。  func learnWebProgramming() {      // ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。 -    err := http.ListenAndServe(":8080", pair{}) -    fmt.Println(err) // 不要无视错误。 +    go func() { +        err := http.ListenAndServe(":8080", pair{}) +        fmt.Println(err) // 不要无视错误。 +    }() + +    requestServer()  }  // 使pair实现http.Handler接口的ServeHTTP方法。  func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {      // 使用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 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)。 | 
