源代码下载: 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 lovelove: 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为一个接口类型,有一个办法Stringtype 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 协定进行许可。