关于go:Y-分钟速成-Go

0次阅读

共计 7777 个字符,预计需要花费 20 分钟才能阅读完成。

源代码下载:learngo-cn.go

创造 Go 语言是出于更好地实现工作的须要。Go 不是计算机科学的最新倒退潮流,但它却提供了解决事实问题的最新最快的办法。

Go 领有命令式语言的动态类型,编译很快,执行也很快,同时退出了对于目前多核 CPU 的并发计算反对,也有相应的个性来实现大规模编程。

Go 语言有十分棒的规范库,还有一个充满热情的社区。

// 单行正文
/* 多行
    正文 */

// 导入包的子句在每个源文件的结尾。// Main 比拟非凡,它用来申明可执行文件,而不是一个库。package main

// Import 语句申明了以后文件援用的包。import (
    "fmt"       // Go 语言规范库中的包
    "io/ioutil" // 蕴含一些输入输出函数
    m "math"    // 数学规范库,在此文件中别名为 m
    "net/http"  // 一个 web 服务器包
    "os"        // 零碎底层函数,如文件读写
    "strconv"   // 字符串转换
)

// 函数申明:main 是程序执行的入口。// 不论你喜爱还是不喜爱,反正 Go 就用了花括号来包住函数体。func main() {
    // 往规范输入打印一行。// 用包名 fmt 限度打印函数。fmt.Println("你好世界")

    // 调用以后包的另一个函数。beyondHello()}

// 函数能够在括号里加参数。// 如果没有参数的话,也须要一个空括号。func beyondHello() {
    var x int   // 变量申明,变量必须在应用之前申明。x = 3       // 变量赋值。// 能够用:= 来偷懒,它主动把变量类型、申明和赋值都搞定了。y := 4
    sum, prod := learnMultiple(x, y)        // 返回多个变量的函数
    fmt.Println("sum:", sum, "prod:", prod) // 简略输入
    learnTypes()                            // 少于 y 分钟,学的更多!}

/* <- 快看快看我是跨行正文_(:з」∠)_
Go 语言的函数能够有多个参数和 * 多个 * 返回值。在这个函数中,`x`、`y` 是参数,`sum`、`prod` 是返回值的标识符(能够了解为名字)且类型为 int
*/
func learnMultiple(x, y int) (sum, prod int) {return x + y, x * y // 返回两个值}

// 内置变量类型和关键词
func learnTypes() {
    // 短申明给你所想。str := "少谈话多读书!" // String 类型

    s2 := ` 这是一个
能够换行的字符串 ` // 同样是 String 类型

    // 非 ascii 字符。Go 应用 UTF- 8 编码。g := 'Σ' // rune 类型,int32 的别名,应用 UTF- 8 编码

    f := 3.14195 // float64 类型,IEEE-754 64 位浮点数
    c := 3 + 4i  // complex128 类型,外部应用两个 float64 示意

    // var 变量能够间接初始化。var u uint = 7  // unsigned 无符号变量,然而实现依赖 int 型变量的长度
    var pi float32 = 22. / 7

    // 字符转换
    n := byte('\n') // byte 是 uint8 的别名

    // 数组(Array)类型的大小在编译时即确定
    var a4 [4] int              // 有 4 个 int 变量的数组,初始为 0
    a3 := [...]int{3, 1, 5}     // 有 3 个 int 变量的数组,同时进行了初始化

    // 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)         // * 取值

    // Map 是动静可增长关联数组,和其余语言中的 hash 或者字典类似。m := map[string]int{"three": 3, "four": 4}
    m["one"] = 1

    // 在 Go 语言中未应用的变量在编译的时候会报错,而不是 warning。// 下划线 _ 能够使你“应用”一个变量,然而抛弃它的值。_, _, _, _, _, _, _, _, _, _ = 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() // 回到流程管制}

// 和其余编程语言不同的是,go 反对有名称的变量返回值。// 申明返回值时带上一个名字容许咱们在函数内的不同地位
// 只用写 return 一个词就能将函数内指定名称的变量返回
func learnNamedReturns(x, y int) (z int) {
    z = x * y
    return // 隐式返回 z,因为后面指定了它。}

// Go 全面反对垃圾回收。Go 有指针,然而不反对指针运算。// 你会因为空指针而犯错,然而不会因为减少指针而犯错。func learnMemory() (p, q *int) {
    // 返回 int 型变量指针 p 和 q
    p = new(int)    // 内置函数 new 分配内存
    // 主动将调配的 int 赋值 0,p 不再是空的了。s := make([]int, 20)    // 给 20 个 int 变量调配一块内存
    s[3] = 7                // 赋值
    r := -2                 // 申明另一个局部变量
    return &s[3], &r        // & 取地址
}

func expensiveComputation() int {return 1e6}

func learnFlowControl() {
    // if 须要花括号,括号就免了
    if true {fmt.Println("这句话必定被执行")
    }
    // 用 go fmt 命令能够帮你格式化代码,所以不必怕被人吐槽代码格调了,// 也不必容忍他人的代码格调。if false {// pout} else {// gloat}
    // 如果太多嵌套的 if 语句,举荐应用 switch
    x := 1
    switch x {
    case 0:
    case 1:
        // 隐式调用 break 语句,匹配上一个即进行
    case 2:
        // 不会运行
    }
    // 和 if 一样,for 也不必括号
    for x := 0; x < 3; x++ { // ++ 自增
        fmt.Println("遍历", x)
    }
    // x 在这里还是 1。为什么?// for 是 go 里惟一的循环关键字,不过它有很多变种
    for { // 死循环
        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}
    // 闭包函数
    xBig := func() bool {return x > 100 // 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
}

// 定义 pair 为一个构造体,有 x 和 y 两个 int 型变量。type pair struct {x, y int}

// 定义 pair 类型的办法,实现 Stringer 接口。func (p pair) String() string { // p 被叫做“接收器”// Sprintf 是 fmt 包中的另一个私有函数。// 用 . 调用 p 中的元素。return fmt.Sprintf("(%d, %d)", p.x, p.y)
}

func learnInterfaces() {
    // 花括号用来定义构造体变量,:= 在这里将一个构造体变量赋值给 p。p := pair{3, 4}
    fmt.Println(p.String()) // 调用 pair 类型 p 的 String 办法
    var i Stringer          // 申明 i 为 Stringer 接口类型
    i = p                   // 无效!因为 p 实现了 Stringer 接口(相似 java 中的塑型)// 调用 i 的 String 办法,输入和下面一样
    fmt.Println(i.String())

    // fmt 包中的 Println 函数向对象要它们的 string 输入,实现了 String 办法就能够这样应用了。//(相似 java 中的序列化)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" 用来判断有没有失常工作
    m := map[int]string{3: "three", 4: "four"}
    if x, ok := m[1]; !ok { // ok 为 false,因为 m 中没有 1
        fmt.Println("别找了真没有")
    } else {fmt.Print(x) // 如果 x 在 map 中的话,x 就是那个值喽。}
    // 谬误可不只是 ok,它还能够给出对于问题的更多细节。if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value
        // 输入 "strconv.ParseInt: parsing"non-int": invalid syntax"
        fmt.Println(err)
    }
    // 待会再说接口吧。同时,learnConcurrency()}

// c 是 channel 类型,一个并发平安的通信对象。func inc(i int, c chan int) {c <- i + 1 // <- 把左边的发送到右边的 channel。}

// 咱们将用 inc 函数来并发地减少一些数字。func learnConcurrency() {
    // 用 make 来申明一个 slice,make 会调配和初始化 slice,map 和 channel。c := make(chan int)
    // 用 go 关键字开始三个并发的 goroutine,如果机器反对的话,还可能是并行执行。// 三个都被发送到同一个 channel。go inc(0, c) // go is a statement that starts a new goroutine.
    go inc(10, c)
    go inc(-805, c)
    // 从 channel 中读取后果并打印。// 打印出什么货色是不可预知的。fmt.Println(<-c, <-c, <-c) // channel 在左边的时候,<- 是读操作。cs := make(chan string)       // 操作 string 的 channel
    cc := make(chan chan string)  // 操作 channel 的 channel
    go func() { c <- 84}()       // 开始一个 goroutine 来发送一个新的数字
    go func() { cs <- "wordy"}() // 发送给 cs
    // Select 相似于 switch,然而每个 case 包含一个 channel 操作。// 它随机抉择一个筹备好通信的 case。select {
    case i := <-c: // 从 channel 接管的值能够赋给其余变量
        fmt.Println("这是……", i)
    case <-cs: // 或者间接抛弃
        fmt.Println("这是个字符串!")
    case <-cc: // 空的,还没作好通信的筹备
        fmt.Println("别瞎想")
    }
    // 下面 c 或者 cs 的值被取到,其中一个 goroutine 完结,另外一个始终阻塞。learnWebProgramming() // Go 很适宜 web 编程,我晓得你也想学!}

// http 包中的一个简略的函数就能够开启 web 服务器。func learnWebProgramming() {
    // ListenAndServe 第一个参数指定了监听端口,第二个参数是一个接口,特定是 http.Handler。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("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 官方网站找到。在那里你能够取得教程参考,在线试用,和更多的材料。在简略的尝试过后,在官网文档那里你会失去你所须要的所有材料、对于编写代码的标准、库和命令行工具的文档与 Go 的版本历史。

强烈推荐浏览语言定义局部,很简略而且很简洁!(赶时髦!)

你还能够返回 Go 在线体验核心,在浏览器里批改并运行这些代码,肯定要试一试哦!你能够将 https://play.golang.org 当作一个 REPL,在那里体验语言个性或运行本人的代码,连环境都不必配!

学习 Go 还要浏览 Go 规范库的源代码,全副文档化了,可读性十分好,能够学到 go,go style 和 go idioms。在文档中点击函数名,源代码就进去了!

Go by example 也是一个学习的好中央。

Go Mobile 增加了对挪动平台的反对(Android and iOS)。你能够齐全用 go 语言来发明一个 app 或编写一个能够从 Java 或 Obj- C 调用的函数库,敬请参考 Go Mobile page。

有倡议?或者发现什么谬误?在 Github 上开一个 issue,或者发动 pull request!

原著 Sonia Keys,并由 2 个好心人批改。
© 2022 Sonia Keys, pantaovay, lidashuang, Tim Zhang
本作品采纳 CC BY-SA 3.0 协定进行许可。

正文完
 0