第四章 做算数(公式、变量和函数)
这一章,将指挥电脑做算术,逐渐熟悉编程。
4.1 写程序的地方
前回我们在 hello 目录里面,创建了第一个程序。之后你可以重复使用该目录,也可以新建一个别的目录。请按照您的喜好选择。
如果要新建目录,请参考上一章的内容,用 VSCode 打开目录,再初始化 go mod 。
4.2 示例程序的说明
下面的程序里面的 package main 和 import "fmt" 等等,在不需要重复说明时会被省略,但实际上代码还是需要写的,请不要删除。
4.3 显示数字
想要显示数字,请在 fmt.Println 函数中的 () 内容设置为数字。
package main
import "fmt"
func main() {
fmt.Println(42)
}
$ go run .
42
4.4 计算式
Go 中,可以使用的主要的算术运算符如下所示。
加法和减法大家很熟悉,但其他符号可能会让你感到新奇。
这些都是编程世界中常见的符号。尤其是日常中不太常见的“取余”计算,在游戏编程中经常会用到。
1 + 2 // 加法
1 - 2 // 剑减法
1 * 2 // 乘法
1 / 2 // 除法
1 % 2 // 割求余
这些计算,也有“优先级”这个概念。乘法、除法、取余的优先级,高于加法和减法。此外,也可以使用括号 () 来改变默认的优先顺序。
func main() {
fmt.Println(1 + 2*3) // 7
fmt.Println((1 + 2) * 3) // 9
}
Go 提供了一种根据优先级等前提条件,自动设置代码格式(比如间距多少,在何处不换行)的格式化功能(go fmt)。
虽然无法设置自己喜欢的代码风格,但因为可以“让所有人都把代码轻松地格式化成标准格式,方便所有人阅读”,我们应该接受这一点。
4.5 小数计算
在 Go 中,整数和小数有明确的区别。整数与整数的计算,结果会去掉小数点的部分,变为整数。例如 1 / 2 的结果是 0 。
func main() {
fmt.Println(1 / 2)
}
$ go run .
0
进行小数计算时,请明确使用小数(也叫做浮点数),例如 1 应该写成 1.0 。
func main() {
fmt.Println(1.0 / 2.0)
}
$ go run .
0.5
[面向有经验的人] 浮动小数与字面量
字面量(包括 Go 中的常量)是一种与普通数值类型略有不同的类型( untyped ),在类型转换方面,会比普通类型宽松一些。
此外,浮动小数点常量在编译时以任意精度(实际上,由于实现上的原因为 256 位)进行计算,因此基本不需要担心误差等问题。
4.6 变量
使用变量, 可以为数据命名并临时存起来(虽然保存了,但仅在程序运行期间可用)。通过使用变量,可以多次使用相同的数据。
以下是变量最简单的用法。
package main
import "fmt"
func main() {
level := 50
fmt.Println(level)
}
$ go run .
50
将值保存到名为 level 的变量中,并显示这个值。
声明与赋值
特殊符号 := ,同时声明和赋值变量的记号。声明是“新建”数据,赋值是“覆盖”已有数据。为了更深入地理解这两个词,我们来看一下“声明和赋值分开写”的语法。
先声明,后赋值的语法:
func main() {
// 先声明
var level int
// 然后代入数值(赋值)
level = 50
fmt.Println(level)
}
Go以 var 参数名称 参数类型 的语法形式声明变量、用 变量名 = 值 的形式赋值。
关于变量类型这个概念,稍后会解释。总之此处的 int, 代表的是整数类型。
变量声明(新建)只能做一次,但赋值(覆盖)可以多次重复很多次。
func main() {
var level int
// var level int ←无法用同一个名字再次声明
level = 50
fmt.Println(level)
level = 100
fmt.Println(level)
}
[面向有经验的人] 作用域
Go 变量(或者说所有标识符)有作用域(有效范围)。作用域由块( {} 包起来的部分)分隔。在作用域内声明的变量,仅在该作用域内有效,无法从作用域外访问。
不能重复声明变量,严格意义上来说是“在同一作用域内”不能再次声明同一变量。
但在不同作用域中,可以声明同名的变量。重名的时候,更窄的作用域中声明的同名变量,会优先生效。因此范围更广的变量会被隐藏,在该作用域内无法访问。这被称为变量遮蔽。
编程中,变量遮蔽(英语:variable shadowing,或称变量隐藏)指的是:当新变量与旧有变量同名,此名称暂时不再可用于访问旧有变量。
不过,在大多数情况下,变量的声明和赋值会同时完成。同时做声明和赋值的时候,可以省略变量类型,写起来更省事。
无论用哪种语法,变量总是可以多次赋值,这一点不会变。
func main() {
var level = 50 // 声明和赋值同时进行,此时,表示类型的 int 可以省略不写
fmt.Println(level)
level = 100 // 再次赋值
fmt.Println(level)
}
此外,在函数内部,可以使用符号 := 来省略 var 这个关键字,使声明和赋值的语句更简洁,这是最常用的语法。
刚刚的程序,声明和赋值语句的等效写法:
func main() {
level := 50 // 声明与赋值
fmt.Println(level)
level = 100 // 再次赋值
fmt.Println(level)
}
4.7 变量和计算式
变量可以像普通数字一样,混用在算式中、参与计算。
func main() {
level := 50
waza := 100 // 盾甲龙兽
attack := 182
defense := 189
maxDamage := level*2/5 + 2
maxDamage = maxDamage*waza*attack/defense/50 + 2
fmt.Println("最大伤害", maxDamage) // 最大伤害 44
}
此外,还有一种同时“计算”与“赋值”的省略写法:
func main() {
hp := 100
hp += 20 // 与 hp = hp + 20 的意义相同
fmt.Println(hp) // 120
hp -= 50 // 与 hp = hp - 50 的意义相同
fmt.Println(hp) // 70
// *=, /=, %= 也遵循同样的规则
}
hp = hp + 20这个等式,在数学中不成立。但编程领域的=号,其实是表示代入(覆盖)的符号。请把这里的等号,当作和数学里的等号不同的符号来看。如果实在无法适应,请在心中将=替换为⇐(表示数据流动方向的箭头) 。
4.8 函数
函数是处理的集合。例如 fmt.Println 函数,是“执行在屏幕上显示文本的处理”的函数。
函数可以使用 () 接收输入。这些输入称为参数。给函数提供输入,称为传递参数(简称“传参”)。
同时传递多个参数,需要用逗号 , 分隔。例如 fmt.Println 函数,就可以把多个参数用空格连接,并把这些内容显示到屏幕上。
fmt.Println("哈哈", "呵呵")
$ go run .
哈哈 呵呵
函数不仅接受输入,还会输出计算或处理的结果。这被称为返回值。
fmt.Println 函数没有返回值,因此我们介绍另一个新函数——
max 函数,返回参数中最大值。
func main() {
fmt.Println(max(3, 4, 5)) // 5
}
这里的 () 有两层,可以简单地认为, max(3, 4, 5) 的计算完成后,fmt.Println()括号里面将被替换为 5 。
fmt.Println(max(3, 4, 5))
// max(3, 4, 5)的计算完成之后、↓将会等效于下面的式子
fmt.Println(5)
参数和返回值,可以混在一起用。
看一下这个程序,让我们来思考一下 fmt.Println 函数会拿到几个参数。
func main() {
fmt.Println("最大值是", max(3, 4, 5), "。最小值", min(3, 4, 5), "。")
}
本章总结
- 虽然和数学符号不一样,但在 Go 里面,也可以做算术。
- 算式有优先级这个概念。可以通过括号,调整优先级顺序。
- 使用变量可以给数据起名,临时保存数据。
- 通过传递参数和接收返回值,可以调用函数(将一些处理,整合在一起处理块)。