├── 0-开篇 ├── 何为代码.md ├── 引子.md ├── 编程的尿性.md └── 编译器与代码.md ├── 1-基础 ├── 作用域.md ├── 函数.md ├── 数据类型与变量.md ├── 流程控制-判断.md ├── 流程控制-循环.md └── 输入输出.md ├── 2-数据结构 ├── map.md ├── slice.md └── struct.md ├── LICENSE └── README.md /0-开篇/何为代码.md: -------------------------------------------------------------------------------- 1 | # 何为代码 2 | 3 | 什么是代码呢?代码就是我们遵循特定的语法,去写些东西。 4 | 5 | 写这些东西干什么呢?他们是怎么用的呢?怎么跑起来的呢? 6 | 7 | 首先,你并不需要知道他们是怎么跑起来的,这是编译器干的事情,我们在这里只要学所谓的「语法」就好。 8 | 9 | 我们写代码到底在写什么? 10 | 11 | 你可以简单地理解为,一行行的代码组成了一堆指令,我们用机器能听得懂的语言对其发号施令,它会严格按照要求执行。 12 | 13 | 这时候,你的脑子里可能有这样一个画面:有一个机器人,在听到你的指令后,执行一系列的操作。 14 | 15 | 我们不妨再大胆点,正如小册子的题目那样,「World」,编程更是对真实世界的模拟和抽象。我们除了向连续地发指令,或者说一步步求解问题那样;还可以以模拟世界的方法进行编程,例如说我们可以利用代码模拟一个小车,它有各种组件,还能跑,我们还可以造个按钮,定义如果按下它会发生什么。 16 | -------------------------------------------------------------------------------- /0-开篇/引子.md: -------------------------------------------------------------------------------- 1 | ## 引子 2 | 3 | 可以先简单地浏览一遍我前些天写的文章: [编程入门之道](https://hdu-cs.wiki/3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.0%20%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8%E4%B9%8B%E9%81%93.html) 4 | -------------------------------------------------------------------------------- /0-开篇/编程的尿性.md: -------------------------------------------------------------------------------- 1 | # 编程的尿性 2 | 3 | 这里我想说的是,编程语言是一门很**严格**的语言,它不像中文的语法那样随意,很多时候稍微替换一下就会出错,想当然的一些尝试大部分时候都会是错的。 4 | 5 | 所以这告诉我们: 6 | 7 | * 编程是非常注重实战的,不要光看,看了一定要多敲! 8 | * 不要问这样并不行,是不是该那样,直接敲进去点一下运行看结果! 9 | 10 | 以及,编程是在反复的编写、运行、调试中度过的,大家需要不断地锻炼自己的快速学习、试错、排错、搜索能力。 11 | -------------------------------------------------------------------------------- /0-开篇/编译器与代码.md: -------------------------------------------------------------------------------- 1 | # 编译器与代码 2 | 3 | 大家都知道,编程又叫写代码,所以「代码」是编程中的一个很重要的元素。 4 | 5 | 大家又知道,又有一个说法叫「编程语言」,所以本质上,写代码也就是「用一种特定的语法进行写作」。 6 | 7 | 相比于中文这样的「自然语言」,是给人听的,或者说是由人解读的。 8 | 9 | 那么,编程语言,是谁解读的呢? 10 | 11 | 你很聪明,答案就是题目本身:「编译器」。 12 | 13 | 简单来说,就是写了代码之后得有个东西去解读、去解释、去编译、去运行、去构建你的代码。(前面有一连串名词,你可能就只能看懂一两个,没事,你不用去搜,现在可以粗浅地把他们当成一个意思,等后面再去搜)。 14 | 15 | 所以初学编程,我们需要学两个东西:「代码本身」,「怎么去跑代码」。 16 | 17 | 至于后者,正如我在「编程入门之道」中提到的,现在别管复杂的编译环境安装,先以最简单最快的办法进入到具体的代码学习中去。 18 | 19 | 这里我推荐你三个方式: 20 | 21 | 1. [Go语言官方教程](https://go.dev/tour/welcome/1),是个网页版教程,网页右侧就能直接敲代码然后运行 22 | 2. GoLand,是个很好用但安装很简单的专门用来写 Go 的软件。可以搜一下然后下载,需要付费,能免费试用30天。学生的话可以先试用着,有空的时候去用学生身份免费激活一下就好,激活方式网上搜。搜索关键词:JetBrain、学生。 23 | -------------------------------------------------------------------------------- /1-基础/作用域.md: -------------------------------------------------------------------------------- 1 | # 作用域 2 | 3 | 4 | 5 | 6 | ## TODO 重写 7 | 8 | 惭愧,我还没想好能怎么简单且易懂地讲述「包与可见性」。 9 | 10 | 值得一提的是,每种编程语言的「包」的概念相差都比较大,本文主要针对 Go 语言。 11 | 12 | 之前我们写代码可能都是在同一个文件里写。当我们的代码越来越多的时候,我们会有许多的代码文件,甚至有很多层文件夹。大家可以狭义地把「文件夹」理解成「包」。同一个文件夹下的项目就是在同一个包内。 13 | 14 | 如果所有的函数、变量等内容全在同一个「包」内,那他们的互相调用和访问是几乎畅通无阻的。可以随便调用。 15 | 16 | 如果我们想调用其他包的函数怎么办,比如 `"fmt"` 和 `"time"` 肯定和我们自己写的程序不在一个包内,怎么调用? 17 | 18 | 你可能注意到了,很简单,就是 `import "包名"`,然后再用 `包名.函数名(...)` 或 `包名.变量名` 的方法来调用。 19 | 20 | 但并不是 `import` 了一个包就能用这个包里所有的内容。很多时候,我们不希望自己写的所有内容都能被其他包调用到,更多时候大部分函数和变量没有必要暴露给其他包使用。这时候,就是所谓的「可见性」了。 21 | 22 | 我们可以设置函数、变量、类型等等一系列内容「包外不可见」(注意是包外不块见,同一个包内一定是全部可见的)。这样这样这里的代码被其他包引用了,也可以保证其他包无法调用某些内容。 23 | 24 | 「包外可见」又见「导出」,「包外不可见」又叫「非导出」。 25 | 26 | 那么 Go 语言是怎么设定可见性的呢? 27 | 28 | 还是很简单,开头第一个字母大写的变量名、函数名等就是包外可见。下划线和中文视为小写。 29 | -------------------------------------------------------------------------------- /1-基础/函数.md: -------------------------------------------------------------------------------- 1 | # 函数 2 | 3 | 编程里的函数和数学里的函数不是一个概念。 4 | 5 | 函数是什么?其实你之前就已经接触过函数了,`fmt.Println` 中的 `Println` 就是函数。 6 | 7 | 大多数时候,我们写的代码不会只被用一次。比如前面的通过出生年和当前年算年龄的代码,以后还可能会用来算大明的年龄。重新粘贴代码显然是不明智的,我们能不能把复杂的代码片段保存起来,以后方便地重用呢? 8 | 9 | 当然可以,这就是函数。 10 | 11 | `fmt.Println` 中的 `Println` 就是函数,把内容输出到屏幕上有着一系列复杂的操作。所以每个编程语言都会预定义一些函数给开发者使用,我们自己写代码的时候不需要关注语言怎么和硬件交互怎么把内容弄到屏幕上显示出来。我们只要知道有个 `fmt.Println` 函数,只要传进去内容,它就能做到把东西打印到屏幕上,就够了。 12 | 13 | 这就像你双击电脑上的图标,就能打开软件一样;或者说只要投个币,旋转小马就会转一样。把复杂的操作封装起来,给定的输出会触发相应的操作,同时还能得到相应的结果,这就是函数了。 14 | 15 | 下面看一段简单的代码: 16 | 17 | ```go 18 | func GetAge(birthYear int, nowYear int) (age int) { 19 | fmt.Println("传入函数的出生年是 %d", birthYear) 20 | fmt.Println("传入函数的当前年是 %d", nowYear) 21 | return nowYear - birthYear 22 | } 23 | 24 | func main() { 25 | birthYearOfXiaoMing, nowYearOfXiaoMing := 2006, 2022 26 | fmt.Printf("小明的年龄是:%d\n", GetAge(birthYearOfXiaoMing, nowYearOfXiaoMing)) 27 | } 28 | ``` 29 | 30 | 可以看到我们定义了一个算年龄的函数, 31 | 32 | * 其中 `func` 是关键字,表明这是个函数; 33 | * `birthYear int, nowYear int` 是形式参数列表,简称「形参」 34 | * `age int` 是返回值,就是函数运算的结果。 35 | 36 | ```go 37 | fmt.Printf("小明的年龄是:%d\n", GetAge(birthYearOfXiaoMing, nowYearOfXiaoMing)) 38 | 39 | // 等同于 40 | 41 | age := GetAge(birthYearOfXiaoMing, nowYearOfXiaoMing) // GetAge 有个返回值,赋给了 age 42 | fmt.Printf("小明的年龄是:%d\n", age) 43 | ``` 44 | 45 | * 大括号 `{}` 围起来的是函数体, 也就是我们封装起来的复杂的操作。 46 | 47 | * `birthYearOfXiaoMing, nowYearOfXiaoMing` 是实参,即我们实际传递给函数的数据。 48 | 49 | 调用的时候,直接用「函数名+实参列表」就行,如 ` GetAge(2006, 2022)`,示例中是传了两个变量,效果是一样的。 50 | 51 | 可以看到,实参和形参名字可以不一样。形参其实只是代表这里是个什么类型的什么值,调用的时候是传常量还是变量,甚至传个表达式都没有问题,因为他们最终的计算结果都是个值。 52 | 53 | 比如 `GetAge(1+2+3, 3+4*5)`,又比如 `fmt.Printf("小明的年龄是:%d\n", GetAge(birthYearOfXiaoMing, nowYearOfXiaoMing))` 这一行,其实就是把 `GetAge(birthYearOfXiaoMing, nowYearOfXiaoMing)` 这个函数调用作为一个整体传进了 `fmt.Printf` 里面,因为本质上 `GetAge` 的函数调用返回的就是一个值。 54 | 55 | * 所以再归纳一下,函数就是可以封装一系列复杂的操作(放到函数体里面),方便以后复用。 56 | * 同时,为了增加灵活性,可以有任意个输入的变量,即形参,这样每次调用都能做不同的操作。 57 | * 最后还有返回值,可以把运算的结果告诉调用者。 58 | 59 | 所以上面这三个就是函数的核心,其他的各种变体都是围绕这个展开的。 60 | 61 | 我们尝试变一下,还是以计算年龄这个函数为例: 62 | 63 | ```go 64 | func GetAge(birthYear int, nowYear int) int { 65 | return nowYear - birthYear 66 | } 67 | ``` 68 | 69 | 这段的变化是,返回值从 `age int` 变成了 `int`,即只留下了类型删去了变量名。因为最后调用即 `age := GetAge(1, 2)` 的时候得到的结果会赋给新的变量,所以调用方只要知道类型就行了,变量名会被重写。(建议:除非返回值非常清楚,否则建议带上变量名,增加可读性) 70 | 71 | ```go 72 | func GetAge(birthYear, nowYear int) int { 73 | return nowYear - birthYear 74 | } 75 | ``` 76 | 77 | 这里主要是参数列表中少了一个 `int` 类型,因为这两个形参是同一个类型,所以可以省略一个,和变量定义的时候同理。 78 | 79 | ```go 80 | func GetAge(birthYear int, nowYear int) (age int, ageNextYear int) { 81 | age := nowYear - birthYear 82 | return age, age+1 83 | } 84 | ``` 85 | 86 | 这里是返回值变成了两个。Go 支持任意多个返回值。 87 | 88 | ```go 89 | func GetAge(birthYear, nowYear int) { 90 | fmt.Printf("年龄是 %d", nowYear - birthYear) 91 | } 92 | ``` 93 | 94 | 既然支持任意个返回值,当然也可以没有返回值。 95 | 96 | ```go 97 | func DogSpeak() { 98 | fmt.Println("汪汪汪!") 99 | } 100 | ``` 101 | 102 | 既然可以没有返回值,那么形参列表也可以是空。 103 | 104 | 其实还有其他的骚操作,这里就不一一举例了。 105 | 106 | 最后再来个例子: 107 | 108 | ```Go 109 | package main 110 | import ( 111 | "fmt" 112 | "time" 113 | ) 114 | 115 | func GetAge(birthYear int) int { 116 | nowYear := time.Now().Year() 117 | return nowYear - birthYear 118 | } 119 | 120 | func main() { 121 | birth := 2006 122 | fmt.Printf("小明今年的年龄是:%d\n", GetAge(birth)) 123 | } 124 | ``` 125 | 126 | `time.Now()` 是 Go 自带的函数,可以获取当前的时间。继续 `.Year()` 就可以获取当前年,这样我们就获得了一个真正的获取年龄的好用的函数了! 127 | 128 | (至于 `.Year()` 又是什么语法,我们后面再讲。) 129 | -------------------------------------------------------------------------------- /1-基础/数据类型与变量.md: -------------------------------------------------------------------------------- 1 | # 数据类型与变量 2 | 3 | 之前提到过编程是「模拟世界」,不过我们先简单点,从「做数学题」开始。 4 | 5 | ## 数据类型 6 | 7 | 就像我们认识世界的时候,喜欢各种分类一样,分成动物和植物,编程里也会给各种分类。比如给所有的「数据」做分类,不同的数据大概可以分为几个「类型」,这就是「数据类型」。 8 | 9 | 比如我们可以简单地把数据分成「字符类型」的,和「数字类型」的。 10 | 11 | 做数学题的第一步是什么?——写「解」,或者「证明」。 12 | 13 | 我们如何去模拟这个「解」、「证明」,或者其他这种文字性的描述?编程里有个概念叫「字符串」,用来表示所谓的「字符」。不同右语言表示字符串的方式都不一样,在 Go 里是用双引号,像这样:`"解"`,`"∴"`。字符串类型在 Go 中用 `string` 表示,其他语言差不多但有区别。 14 | 15 | 然后就是编程语言如何表示「数字」了。大部分编程语言会把数值类型的值统分为两种:整数和小数。小数也叫「浮点数」。然后每个编程语言又和把整数和小数再细分成很多类型。 16 | 17 | ## 变量 18 | 19 | 有了类型,那么变量是什么?很简单,变量就像方程组里的 `x`, `y` 那样。如果我们做数学题,或者说写代码,写出来的程序全是已经确定的数字,没有任何可变性,那有啥用?代码不就成了一行行的算式了? 20 | 21 | 变量简而言之就是类似于方程组里 `x` 的一个标识,我们可以往里面塞东西。然后把它用于计算和运行程序。 22 | 23 | 值得注意的是,变量是有类型的,且每个变量的类型不能改变。比如你定义了一个用来存整型数字的变量 `num`,那你就不能用它来存 `"解 "` 或者小数一类的东西了。 24 | 25 | 下面看看实际的例子: 26 | 27 | ```go 28 | var prove string 29 | prove = "证明" 30 | ``` 31 | 32 | 上面的 `var` 就是 `variables` 的缩写,`prove` 就是变量的名字,比如你想取个叫 `dog` 的变量也行(注意变量名字尽可能表述清晰)。变量名一般尽量用英文,以及开头一般是字母或下划线(不能是数字),后面可以是字母数字下划线。不同语言有对变量命名的规范。 33 | 34 | 后面的 `string` 就是表示变量是个 `string` 类型。 35 | 36 | 所以 `var prove string` 就是声明/定义了一个 `string` 类型的变量 `prove`。在 Go 里,变量需要先定义再使用。 37 | 38 | `prove = "证明"` 就是让 `prove` 的值变成 `"证明"` ,这在编程里叫「赋值」。 39 | 40 | 再来个例子: 41 | 42 | ```go 43 | var a int 44 | a = 1 45 | var b int 46 | b = a + 2 47 | ``` 48 | 49 | 其中 `int` 是整型变量的一种,Go 还有很多其他的整型变量的类型,如 `int32`;小数类型的话有 `float32`, `float64` 等。 50 | 51 | 所以这个例子很好理解:定义一个 `int` 类型的变量 `a`,赋值为 1,再定义个同类型的 `b`,赋值为 `a+2`。其中 `a` 的值是 1,所以 `b` 的值其实是3。 52 | 53 | 注意不同类型的变量是不能做运算的,比如: 54 | 55 | ```go 56 | var a int 57 | var b float32 58 | var sum float32 59 | sum = a + b // a和b的类型不同,会报错 60 | ``` 61 | 62 | 上面的 `//` 代表注释,注释后面的内容不会被编译器执行,主要是写给人看的,应当养成多写注释的好习惯。 63 | 64 | Go 还有很多声明变量与赋值的语法,这里简单举一些,相信大家看了这篇文章就有看懂其他变量语法教程的能力了。 65 | 66 | ```go 67 | a := 1 68 | ``` 69 | 70 | 这个相当于定义了一个整数型的变量 `a`,并赋值(初始化)为 1。这里没有声明类型,但是编译器会根据右边的赋值去猜。 71 | 72 | 还有很多玩法,就不一一解释: 73 | 74 | ```go 75 | var num1, num2 int 76 | var num3, num4 int = 3, 4 77 | var num5, str1 = 5.0, "嘿嘿" 78 | ``` 79 | 80 | 还有一点要注意,Go 定义了的变量一定要使用,不然会报错。非常优雅。 81 | 82 | ## 零值 83 | 84 | 前面的变量我们都赋值了,你有没有想过不赋值会发生什么呢? 85 | 86 | 在有些语言里面,不初始化变量(即不赋值),变量里的内容是随机的。 87 | 88 | 但在 Go 里,所有的类型都有「零值」。所有数值类型的零值是 `0`,字符串是 `""`。 89 | 90 | 例如:`var a int`,这时候 a 的值就是0。 91 | 92 | ## 常量 93 | 94 | 与变量相对,不变的量就是常量。比如,`1`,`3.0`,`"嘿嘿"`。 95 | 96 | 还有一种常量大家可能不知道,可以简单理解为:不变的变量。 97 | 98 | 例如:`const Pi int = 3.1415` 99 | 100 | 它和变量的声明几乎一模一样,主要有两个不同,一个是 `var` 关键字变成了 `const`,另一个是值不能修改。 101 | 102 | 那么为什么不直接用 `3.1415` 这种值,还要再定义一个常量呢? 103 | 104 | 因为可读性。 105 | 106 | ## 总结 107 | 108 | 1. 为了表征这个世界,我们需要先定义一些基本的类型。比如:整数、小数、字符串等。 109 | 2. 表示这些数据的方法,可以分为两种:变量和常量。 110 | 3. 每种编程语言的数据类型不尽相同,但大体差不多;声明、定义变量的方式,也同样。 111 | 112 | ## 其他语言的数据类型与变量 113 | 114 | 大家宏观感受一下就好,主要抓住其中的共通之处,或者说整体感觉。 115 | 116 | ### 数据类型 117 | 118 | 在表示整数的数据类型方面: 119 | 120 | - Go 有 `int`,`int32`,`int64` 等 121 | - C 有 `int`,`long`,`short` 等 122 | - Java 有 `int`,`long`,`short` 等 123 | - JavaScript 有 `Number`,既可以表示整数,也可以表示小数 124 | 125 | 在表示小数的数据类型方面: 126 | 127 | - Go 有 `float32`,`float64` 128 | - C 有 `float`,`double` 129 | - Java 有 `float`,`double` 130 | - JavaScript 有 `Number`,既可以表示整数,也可以表示小数 131 | 132 | 在声明、定义变量的方法是: 133 | 134 | - Go 是 `var a int`,`a := 1` 等 135 | - C 是 `int a`,`char b = 'b'` 等 136 | 137 | 可以看到,Go 语言是变量并在前,类型在后;C语言则相反。 138 | 139 | 但无论如何,这些细节,都逃不出整体的框架。 140 | 141 | 142 | -------------------------------------------------------------------------------- /1-基础/流程控制-判断.md: -------------------------------------------------------------------------------- 1 | # 流程控制-判断 2 | 3 | 我们来回顾一下现在已经拥有了哪些能力? 4 | 5 | * 定义不同类型的变量,做各种计算 6 | * 获取用户输入,并将结果输出出来 7 | * 把复杂的可以被重用的代码片段封装成函数 8 | 9 | 我们已经拥有了以上的能力,再加上已经有了各种各样的现成的好用的「函数」。大部分时候写代码,只不过是各种函数的组合。 10 | 11 | 比如,我们想写个输入小明的生日和祝福的话语,程序将会在小明生日的时候给他发送短信。我们大概只需要找到一个获取当前日期的函数,再来个给指定人发送信息的「函数」,最后再让程序一直跑下去不退出就好了。加一些简单代码的串联,就能写出这样的程序。 12 | 13 | 但,是不是还差了点什么? 14 | 15 | ## If-else if-else 16 | 17 | 想卖关子也没法卖啊哈哈哈,题目已经出卖了——「流程控制-判断」。 18 | 19 | 下面是一个「一元二次方程求解」的例子 20 | 21 | ```go 22 | import "math" 23 | 24 | // Solve 求解一个一元二次方程, 25 | // 需将方程组化为 ax^2+bx+c=0 的形式 26 | func Solve(a, b, c float64) (x1, x2 float64) { // float64 是小数类型的一种 27 | t := b*b - 4*a*c 28 | // math.Sqrt 是开根号函数 29 | return (-b + math.Sqrt(t)) / (2 * a), (-b - math.Sqrt(t)) / (2 * a) 30 | } 31 | ``` 32 | 33 | 大家对着注释看,这段代码肯定能看懂。 34 | 35 | 但是它少了一样东西,没有对 `b*b - 4*a*c` 是否大于等于 0 的判断! 36 | 37 | 为什么没有?因为前面根本没教!现在马上教给你! 38 | 39 | 我直接贴代码不说话: 40 | 41 | ```go 42 | flag := 1 43 | if flag > 1 { 44 | fmt.Println("哦豁a大于1!") 45 | } 46 | ``` 47 | 48 | 其中 `if` 是表示判断的关键词,`if` 这个单词的的中文意思就是 「如果」。 49 | 50 | 还可以再加一点东西,我继续不说话: 51 | 52 | ```go 53 | password := "芝麻开门" 54 | if password == "芝麻开门" { // 编程里判断是否相等一般不用 "=",而用"=="。因为"="是赋值 55 | // 这里其实可以写任何行代码,只不过为了方便理解我都只是用了一个简单的输出 56 | fmt.Println("密码正确门开啦!") 57 | } else { 58 | fmt.Println("密码错误!") 59 | } 60 | ``` 61 | 62 | 这里主要就是加了个 `else` 就是「否则」的意思。`if` 后面的是条件,条件成立就执行 `if` 旁边的大括号包裹的内容,不成立就执行 `else` 里的内容。 63 | 64 | 我再贴代码不说话! 65 | 66 | ```go 67 | score := 85 68 | var rank string 69 | if score >= 90 { // 大于等于 70 | rank = "优秀" 71 | } else if score < 90 && score >= 80 { 72 | rank = "良好" 73 | } else if score < 80 && score >= 60 { 74 | rank = "及格" 75 | } else { 76 | rank = "不及格" 77 | } 78 | fmt.Println("小明的成绩评级是:", rank) 79 | ``` 80 | 81 | 上面的代码主要有两个新知识点: 82 | 83 | * `&&` 代表逻辑与,可以理解成「且」,`score < 90 && score >= 80` 就等价于 `80 <= score < 90`。不过大部分程序不能这么写。「且」的意思就是,所有条件都满足才能满足。比如 `score>80 && age<20 && name=="小明"`,筛选出同时满足这三个条件的人。 84 | * `else if`。我很难解释,但是你看代码应该能猜出来啥意思。 85 | 86 | ## 布尔值(bool) 87 | 88 | 大家应该能很轻松地看出来,`if` 和 `else if` 后面的东西是逻辑判断,或者说这个式子的结果应该是「对」或「错」,「满足」或「不满足」。或者更专业些说,就是「真」或「假」,`true` 或 `false`。 89 | 90 | 这种值叫做「布尔值」,编程里面有专门的一种数据类型来存储这种值,就叫「布尔型」,在 Go 里面类型的关键字是 `bool`。这个类型的值取值只有两种,零值是 `false`。比如: 91 | 92 | ```go 93 | var thisBookIsCool bool 94 | thisBookIsCool = true 95 | if thisBookIsCool { 96 | // ... 97 | } 98 | ``` 99 | 100 | 这样就定义了一个 `thisBookIsCool` 的布尔值,并赋为 `true`。同时因为 `if` 后需要跟一个逻辑判断,或者说逻辑表达式,或者说一个式子最后的结果要是 `true` 或 `false`,而布尔值本身就是 `true` 或 `false`,所以可以直接跟在 `if` 后面。 101 | 102 | ## Switch 103 | 104 | 其实只用 `if`, `else if` 和 `else` 三件套就能处理所有的「判断」逻辑,但是许多语言,比如 Go,还支持一种比较优雅的判断的语法,适合判断条件很多的时候。 105 | 106 | 我直接给例子: 107 | 108 | ```go 109 | name := "小明" 110 | switch name { 111 | case "小红": 112 | fmt.Println("欢迎小红,这是位女同学") 113 | // 可以写很多行 114 | // 不是只能写一行 115 | case "小明": 116 | fmt.Println("欢迎小明,这是位男同学") 117 | default: 118 | fmt.Println("欢迎!!!") 119 | } 120 | ``` 121 | 122 | 看代码可以推测出, `switch` 的中文意思是「开关」,我们就把它理解成开关。其中决定开关的是 `swtich` 后面的变量,这次是 `name`。如果值等于 "小红",就.....;如果值等于"小明",就.....;如果从上至下一个个比对都没中,就执行 `default` 里的内容。 123 | 124 | 再来个例子: 125 | 126 | ```go 127 | score := 85 // 实际运行过程中这个 score 不一定是定死的,比如可以是用户输入的 128 | var rank string 129 | switch { 130 | case score >= 90: 131 | rank = "优秀" 132 | case score < 90 && score >= 80: 133 | rank = "良好" 134 | case score < 80 && score >= 60: 135 | rank = "及格" 136 | default: 137 | rank = "不及格" 138 | } 139 | fmt.Println("小明的成绩评级是:", rank) 140 | ``` 141 | 142 | `switch` 后面也可以不带变量,这样的话每个 `case` 后面就是一个逻辑表达式,如果结果为 `true` 就执行对应的 `case` 的内容。 143 | 144 | Go 的 `switch` 还有很多玩法,就不一一展开。所有的判断本质上都是一样的:一个关键字+一个逻辑表达式,如果逻辑表达式最后算出来的结果是 `true`,就执行这个关键字管辖的对应块内的所有代码。 145 | -------------------------------------------------------------------------------- /1-基础/流程控制-循环.md: -------------------------------------------------------------------------------- 1 | # 流程控制-循环 2 | 3 | 有了判断就够了吗?当然不够。 4 | 5 | 编程的一大魅力就是减少重复性工作。 6 | 7 | 来个例子,前面的求根公式的例子的伪代码如下: 8 | 9 | ```text 10 | 输入 a, b, c 11 | 判断 b*b -4*a*c 是否大于等于0 12 | 若>=0: 调用求根公式,输出结果 13 | 否则:告诉用户此方程无实数解 14 | ``` 15 | 16 | ## for 循环 17 | 18 | 用户想多次求解方程怎么办? 19 | 20 | 求解几次就把输入、求解函数调用、输出复制几次? 21 | 22 | 当然有更简单的办法,这就是循环,例如,想无限输出 `Hello World`,就可以这样写: 23 | 24 | ```go 25 | for { 26 | fmt.Println("Hellow World") 27 | } 28 | ``` 29 | 30 | 同理,想无限求解方程,就这么写: 31 | 32 | ```go 33 | for { 34 | // 输入 a, b, c 35 | // 判断 b*b -4*a*c 是否大于等于0 36 | // 若>=0: 调用求根公式,输出结果 37 | // 否则:告诉用户此方程无实数解 38 | } 39 | ``` 40 | 41 | 这么写其实是有问题的,尤其是第一种,这个循环是无限的循环,会疯狂执行下去,比如第一个程序可能一秒能输出几万个甚至更多的 `"Hello World"`,直到程序报错。 42 | 43 | (第二个这么写倒是问题不大,因为输入的时候程序会停住等用户输入,所以第二个程序可以不断地求解方程,直到用户主动把程序关了) 44 | 45 | ## 控制循环次数 46 | 47 | 但我们能不能在程序内优雅地控制重复执行的次数? 48 | 49 | 怎么控制循环的次数呢? 50 | 51 | 其实我们可以换个角度想,如果我们有一个可以退出循环的命令,然后自己记录循环的次数,如果次数达到了就主动退出,代码如下: 52 | 53 | ```go 54 | var countWant, countCurrent = 5, 0 // 假设我们想重复某个代码段 5 次 55 | 56 | for { 57 | if countWant == countCurrent { 58 | break // 如果当前循环的次数达到了预期,就用 break 这个命令退出循环 59 | } 60 | 61 | // 这里可以写 62 | // 你想 63 | // 循环执行的 64 | // 代码 65 | 66 | countCurrent = countCurrent + 1 // 更新当前循环的次数。这里也可以写成 countCurrent += 1,效果一样 67 | } 68 | 69 | fmt.Println("循环退出啦,继续执行 for 循环后面的代码") 70 | // 后面的代码 71 | ``` 72 | 73 | 其中最关键的就是 `break`,可以退出本层的循环,然后继续执行下面的代码。退出本层的循环指的是 `for` 里面还可以继续嵌套 `for`,`break` 只能退出它所在的那层循环。 74 | 75 | ```go 76 | for { 77 | if 1==2 { 78 | break // 第一个 break 79 | } 80 | 81 | for { 82 | if 1==1 { 83 | break // 第二个 break 84 | } 85 | } 86 | fmt.Println("如果第二个 break 生效,代码会到这里继续执行") 87 | } 88 | fmt.Println("如果第一个 break 生效,代码会到这里继续执行") 89 | ``` 90 | 91 | 其实更多时候会用 `range` 循环,但这个要配合后面的内容讲,先不讲。 -------------------------------------------------------------------------------- /1-基础/输入输出.md: -------------------------------------------------------------------------------- 1 | # 输入输出 2 | 3 | 读完[数据类型与变量](数据类型与变量.md)这篇文章,你可能可以写出下面的代码: 4 | 5 | ```go 6 | var firstName string = "小明" 7 | var lastName = "李" 8 | birthYear := "2006" 9 | fullName := lastName + firstName // 这是字符串的拼接操作,用 + 即可 10 | age := 2022 - birthYear 11 | ``` 12 | 13 | 你肯定能看懂这行代码,但你运行了,没有显示出任何东西,你几乎啥都看不到。 14 | 15 | 所以,我们写代码的时候,或者更准确地说,运行代码的时候,是要和程序交互的。 16 | 17 | ## 输出 18 | 19 | 首先,我们要知道,代码执行过程中的一些结果是什么,我们可以让他们显示出来,即「输出」,或者说「打印」。 20 | 21 | 同理,我们还可以输入数据,这个确实就叫「输入」。 22 | 23 | 加个输出,上代码: 24 | 25 | ```go 26 | var firstName string = "小明" 27 | var lastName = "李" 28 | birthYear := 2006 29 | fullName := lastName + firstName 30 | age := 2022 - birthYear 31 | fmt.Println(fullName) 32 | fmt.Println(age) 33 | ``` 34 | 35 | 这时候你会看到有输出了,大概像这样: 36 | 37 | ``` 38 | 李小明 39 | 16 40 | ``` 41 | 42 | 上面的 `fmt.Println` 是怎么来的,为什么能这么写,为什么这么写就能输出出来东西,你现在不用操心。 43 | 44 | 只要知道这么写确实就能输出出来东西就行。 45 | 46 | ## 输入 47 | 48 | 再来加上输入,上代码: 49 | 50 | ```go 51 | var firstName string = "小明" 52 | var lastName = "李" 53 | var birthYear int 54 | 55 | fmt.Scan(&birthYear) // 这里就是获取用户输入,并且把读取到的 int 整数值赋给 birthYear。 56 | // 在运行的窗口里输入 2022,再回车(Enter) 57 | fullName := lastName + firstName 58 | age := 2022 - birthYear 59 | fmt.Println(fullName) 60 | fmt.Println(age) 61 | ``` 62 | 63 | 这样我们就能由用户自定义小明的出生年,然后算年龄了。 64 | 65 | ``` 66 | 李小明 67 | 16 68 | ``` 69 | 70 | ## 简单拓展 71 | 72 | 其实还有很多输入输出的方式,例如 73 | 74 | ```go 75 | fmt.Printf("小明的出生年是%d", 2006) //输出:小明的出生年是2006 76 | dad := "大明" 77 | fmt.Printf("小明的爸爸是%s\n", dad) //输出:小明的爸爸是大明 (并加一个换行) 78 | var birthYear, nowYear = 2006, 2022 79 | fmt.Printf("小明的出生年是%d,今年是%d,所以小明的年龄是%d。\n", birthYear, nowYear, nowYear-birthYear) 80 | // 输出:小明的出生年是2006,今年是2022,所以小明的年龄是16。 81 | ``` 82 | 83 | 这里用的是 `fmt.Printf` 函数,也叫「格式化打印、格式化输出」,其中 `Print` 就是打印,`f` 是 format,`printf` 就不用解释了。 84 | 85 | 所以这里的 `"小明的出生年是%d"`,就是具体的格式化字符串。 86 | 87 | 你唯一不懂的应该就两个地方:`%s` 和 `%d`,以及 `\n`。 88 | 89 | 很简单,`%` 开头的是占位符,后面的字母代表占位符的数据类型,不同类型的数据对应的字母不一样。格式化输出除了能输出各种类型的数据,还能简单设置格式,比如 `%02d` 就能设置输出的数字至少有两位,不足的话左补0。可以用于月份输出的对齐。 90 | 91 | ## 完整代码 92 | 93 | 值得一提的是,完整的代码不是这样的,是这样: 94 | 95 | ```go 96 | package main 97 | import "fmt" 98 | 99 | func main() { 100 | var firstName string = "小明" 101 | var lastName = "李" 102 | var birthYear int 103 | 104 | fmt.Scan(&birthYear) // 这里就是获取用户输入,并且把读取到的 int 整数值赋给 birthYear。 105 | // 在运行的窗口里输入 2022,再回车(Enter) 106 | fullName := lastName + firstName 107 | age := 2022 - birthYear 108 | fmt.Println(fullName) 109 | fmt.Println(age) 110 | } 111 | ``` 112 | 113 | ## 再讲一点 114 | 115 | 如果你把 `fmt.Println` 当作超能力的话,可以把 `fmt` 当成超能力的发起者,而 `Println`, `Printf`, `Scan` 是具体的超能力。这个超能力是 Go 语言为我们提供的,暂时不用操心怎么来的,会用就行。 116 | 117 | 而 `import fmt` 就是和 Go 语言说,我要在代码用超能力了! 118 | 119 | `func main` 就是所谓的主函数,你运行一个程序,Go 怎么知道该从哪里运行呢?——就从 `package main` 里的 `func main` 开始运行。 120 | -------------------------------------------------------------------------------- /2-数据结构/map.md: -------------------------------------------------------------------------------- 1 | ## map 2 | 3 | 写不动了先空着。 4 | 5 | 简而言之 `map` ....,好像很难简而言之。 6 | 7 | 它的中文名叫「映射」,也可以理解为 `python` 的「字典」。 -------------------------------------------------------------------------------- /2-数据结构/slice.md: -------------------------------------------------------------------------------- 1 | ## slice 2 | 3 | 写不动了先空着。 4 | 5 | 简而言之 `slice` 就是能一下子定义一组变量,中文名叫「切片」。 6 | 7 | 比如一个班的学生可以这样写: 8 | 9 | ```go 10 | var studentsOfOneClass []Student // 用了前面定义的 Student 类型 11 | ``` 12 | 13 | (很像 `python` 的列表)。 -------------------------------------------------------------------------------- /2-数据结构/struct.md: -------------------------------------------------------------------------------- 1 | # struct 2 | 3 | 其实学了前面的内容后,我们已经可以实现绝大部分想要的功能了。 4 | 5 | 下面我带大家理一下如何用上面的那些功能去写一个程序: 6 | 7 | 1. 首先弄明白自己要实现的是个什么东西,大概可以分为哪几个模块。模块之前的逻辑(判断、循环)的什么样的。 8 | 2. 每个模块具体如何实现?有哪些代码可以封装成函数以复用? 9 | 3. 遇到不会的地方,可能有两种情况: 10 | 1. 对语法不熟,补一下就好了,几乎没有人能一下子学会哪门编程语言的所有语法的。 11 | 2. 某块功能不知道怎么实现。第一,可以尝试去搜一下你想要的功能描述,大概率能得到现成的解决方案,去学一下别人怎么写的就好。第二,很多特定的软件,比如你想发个短信,这种看起来复杂的对你而言无法想象的功能,大多数时候都有现成的库(库你可以理解为函数的集合),去搜一搜,对照着文档用就好 12 | 13 | 小册子开头我提到还要教你如何去学一门编程语言,其实在我看来主要也是两点,就像你回忆一下我是如何在小册子中引导你那样: 14 | 15 | 1. 首先是任务驱动,你有特定的想做的事情,然后去想着它如何实现,再去自己写也好,边搜现成的方案边学也好。写得越多你就能发现要学的东西越多,久而久之就什么都会写了,或者说看到一个需求马上就会有思路,以及遇到一个新的东西能很快上手。 16 | 2. 然后是,先去最快速地去建立对一个东西的核心的认识。比如我这个小册子到目前为止只介绍了编程中非常少的一部分内容,但却是在核心的,有了这个你能更快地去理解其他的内容,去实现更多的复杂的功能。先建立自己的核心理解,再通过不断学习扩大自己的知识范围。 17 | 18 | ## 为什么有 struct 19 | 20 | 前面的章节基本已经能让你开始实现各种功能了,但正如前文某篇文章所说的,**「编程是对现实世界的模拟」**。 21 | 22 | 遗憾的是我们前面学到的并不能很好的去对这个世界进行建模。就拿数据类型来说,我们只学了基本的数字啊字符串的基本类型。 23 | 24 | 如果我们去描述一个学生的信息的话,我们可能会定义这样几个变量: 25 | 26 | ```go 27 | var name string 28 | var ID string // 学号 29 | var class string 30 | var birthYear int 31 | var gender string 32 | // ... 还有很多其他字段就不一一举例 33 | ``` 34 | 35 | 诚然,我们可以用各种基本的数据类型来定义学生的各个属性。但是,有没有觉得这些属性是「散」的。 36 | 37 | 换句话说,如果上面这些变量模拟了张三这个学生,那么再来个李四怎么办呢?再定义一套 `name2`, `ID2` ...? 38 | 39 | 再来一个呢?疯狂新定义不同名字的变量? 40 | 41 | 有没有什么办法,能把这些变量真正地组合到一起,甚至说新定义个专门用来描述学生的类型呢? 42 | 43 | 上代码: 44 | 45 | ```go 46 | type Student struct { 47 | name string 48 | ID string // 学号 49 | class string 50 | birthYear int 51 | gender string 52 | } 53 | ``` 54 | 55 | 我们直接对着英文猜测含义吧:用 `type` 定义了一个新的数据类型 `Student`,同时这是个 `struct`(结构体)。 56 | 57 | (如前文所述,这个结构体里的 `name`, `class`, `birthYear`, `gender` 开头是小写,非导出,外部的包是无法访问到具体的字段的值的) 58 | 59 | 下面我们可以直接声明 `Student` 类型的变量了: 60 | 61 | ```go 62 | // 一下内容请复制到某个函数内,比如 main 函数 63 | var zhangsan Student // 可以这么定义变量 64 | zhangsan.name = "张三" // 赋值的时候可以对结构体内的字段用 "变量名.字段名=值" 来赋值。你可以把 "A.B" 理解成"A的B"。 65 | zhangsan.birthYear = 2006 66 | zhangsan.ID = "22051620" 67 | // ... 68 | 69 | fmt.Printf("张三的学号是%s\n", zhangsan.ID) // 引用结构体字段的时候也是 "变量名.字段名" 就行。 70 | 71 | lisi := Student{ // 也可以用 := 语法快捷定义 72 | name: "李四", 73 | ID: "22051620", 74 | birthYear: 2002, 75 | gender: "男", 76 | class: "22050516", 77 | } 78 | 79 | fmt.Printf("李四的学号是%s\n", lisi.ID) 80 | fmt.Println(lisi) // 也可以直接输出整个结构体类型,Go对struct设置了默认的输出格式 81 | ``` 82 | 83 | 有了 `struct` (结构体)的话,我们就可以定义更符合现实世界的新类型了。 84 | 85 | 86 | 87 | `struct` 还有很多玩法,比如像 `struct` 里可以嵌套基本的数据类型那样,它里面也可以嵌套 `struct`。 88 | 89 | ```go 90 | type Car struct { 91 | Wheel1 Wheel // 车有四个轮子,每个轮子又是一个 struct 92 | Wheel2 Wheel 93 | Wheel3 Wheel 94 | Wheel4 Wheel 95 | Kind string // 车的类型 96 | Engine Engine // 引擎。前面那个 Engine 是字段名,后面那个 Engine 是类型名。Go 是允许这两个名字重复的。 97 | } 98 | 99 | type Wheel struct { 100 | Radius float64 // 轮子的半径 101 | } 102 | type Engine struct { 103 | Info string 104 | } 105 | 106 | func main() { 107 | var car Car 108 | car.Wheel1 = Wheel{Radius: 123} 109 | car.Wheel2 = Wheel{Radius: 123} 110 | car.Wheel3 = Wheel{Radius: 123} 111 | car.Wheel4 = Wheel{Radius: 123} 112 | car.Engine = Engine{Info: "引擎信息"} 113 | car.Kind = "小轿车" 114 | 115 | bigCar := Car{ 116 | Wheel1: Wheel{Radius: 321}, 117 | Wheel2: Wheel{Radius: 321}, 118 | Wheel3: Wheel{Radius: 321}, 119 | Wheel4: Wheel{Radius: 321}, 120 | Engine: Engine{ 121 | Info: "超大引擎", 122 | }, 123 | Kind: "大轿车", 124 | } 125 | } 126 | 127 | ``` 128 | 129 | (这里 Car 的里面的字段开头都是大写,对其他包可见) 130 | 131 | 132 | 133 | `struct` 还有什么诸如匿名嵌套一类的慢慢学就好~ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # From Golang to the Code World 2 | 3 | 重构中。。。 4 | 5 | ## 我是谁 6 | 7 | 如题,这是一个为编程零基础同学准备的从 Go 语言入门编程的小册子。 8 | 9 | (其实,在近一年后重新看这个小册子,我决定将定位改成,以 Go 语言为例子,与通俗但专业的语言,来讲解对于初学者而言,编程语言的核心要素。) 10 | 11 | ## 我从哪来 12 | 13 | Bird 参与了社团(杭电助手)的学习平台(主要面向新大一)的建设,在建设初期需要准备 Go 语言的基础入门教程。 14 | 15 | 我们本觉得现在的教程已经够丰富了,可以直接丢给新人看。也能省去我们自己「宝贵」的时间。 16 | 17 | 但现在的教程大多又臭又长,以及绝大多数 Go 语言的教程都假设读者已经学会了其他语言,即已经有了基本的编程思想。 18 | 19 | 于是我们决定到处找合适的教程,做一个缝合者,删减与增补多个教程,做成我们自己的教程。 20 | 21 | 但今晚,也就是2022年08月22日的凌晨,Bird 在和一位叫 ZZM(from SRT社团) 的奇人聊了一会后,被他的格局所感动。 22 | 23 | **既然别人的教程都对新人不友好,为什么不自己动手搞一个心目中的完美的Go入门教程?** 24 | 25 | **这不正是自己所热爱的吗?** 26 | 27 | ## 我长什么样 28 | 29 | (即,看完这个小册子,你能获得什么) 30 | 31 | * 首先,**看完这个教程,并不能让你学会 Go 语言**,你甚至可能写不出一行代码 32 | 33 | 我认为,比学语言本身更重要的,是如何去 **「理解编程是什么」,去学「怎么学编程」**。 34 | 35 | 所以,我会像 Go 语言本身的小而美那样, 36 | 37 | * 介绍 Go 语言或者说一门编程语言最核心的东西 38 | * **并传授给你能看得下去其他教程的能力** 39 | 40 | 「From Go」由我来做,「to the Code World」就交给你了。 41 | 42 | ## 特此正名 43 | 44 | Go 语言的正式、官方、真正的名字就是「Go语言」。Golang 只是一个小名,据说为了搜索引擎能更精确地搜到。 45 | 46 | 我给这个小册子起名用「Golang」原因类似,不然名字就会变成:「from go to the code world」,go-to。 47 | 48 | ## 为什么? 49 | 50 | 因为热爱、因为梦想,因为开源是程序员的浪漫。欢迎贡献(PR、Issue等)。 51 | 52 | ## 关于目录 53 | 54 | 本目录主要基于 [Go 语言官方教程](https://tour.go-zh.org/),有一定修改。所以建议读者看到第一章后,边看这个小册子边对着教程相应的章节去学习正经的代码语法和敲代码。 55 | 56 | 但是官方的 Go 语言教程有点简单,推荐同时学习[菜鸟教程](https://www.runoob.com/go/go-tutorial.html)的对应章节,这是一个神奇的几乎拥有所有语言和工具的零基础教程的网站。不评价它的质量如何,但它能恰到好处地讲解每门编程语言所需要知道的核心概念,非常适合新手入门。 57 | 58 | 菜鸟教程里有部分章节比较「迂腐」,比如安装 Go 语言环境,或者说有些东西太细了没必要现在学。如果冲突和我说的比较大的,建议暂时以我的为准,主要是我会选取尽可能简单的路线来带着入门。也可以通过各种方式联系 Bird (例如邮件、QQ群,不要直接打电话哪怕你真的是个猛人能搞到我电话)以确认,我们共同完善。 59 | 60 | ## 目录 61 | 62 | * 章节〇(开篇) 63 | * [引子](0-开篇/引子.md) 64 | * [编译器与代码](0-开篇/编译器与代码.md) 65 | * [何为代码](0-开篇/何为代码.md) 66 | * [编程的尿性](0-开篇/编程的尿性.md) 67 | * 章节一(基础) 68 | * [数据类型与变量](1-基础/数据类型与变量.md) 69 | * [输入输出](1-基础/输入输出.md) 70 | * [函数](1-基础/函数.md) 71 | * [作用域](1-基础/作用域.md) 72 | * [流程控制-判断](1-基础/流程控制-判断.md) 73 | * [流程控制-循环](1-基础/流程控制-循环.md) 74 | * 章节二(数据结构) 75 | * [struct](2-数据结构/struct.md) 76 | * [slice](2-数据结构/slice.md) 77 | * [map](2-数据结构/map.md) 78 | * 章节三(面向对象) 79 | * 方法和类 80 | * 接口 81 | * 章节四 82 | * 并发 83 | 84 | ## 再唠两句 85 | 86 | 这里写一些杂七杂八的说明。 87 | 88 | ### 没讲到的内容 89 | 90 | 局部变量与全局变量及变量作用域、错误处理、指针、defer、range。 91 | --------------------------------------------------------------------------------