學(xué)Go語言:循環(huán)與條件判斷教學(xué)
让我们继续我们的 Go 旅程。上次,我们在 WSL 中安装并配置好了 Go,并介绍了值、变量和常量等基础知识。这次,我们将深入探讨 Go 中的 for 循环和条件判断,它们是 Go 语言中决策和循环的基础。如果你想跟着一起学习,可以参考 Go by Example 中的 for 循环部分。
在本文的最后,我们还将快速地介绍一下如何使用简单的 Dockerfile
在Docker 中运行 Go 程序,让它们易于打包并可以在任何地方运行。
在讨论for
循环时,通常直接说“循环”更简洁,但在技术文档中保留for
有助于保持术语的一致性。
我们的第一个重点是简单的 for 循环语句。这里举的例子有几种不同的循环,我们来挨个看看。
i := 1
for i <= 3 {
println(i)
i = i + 1
}
// 这是一个简单的循环,我们从1开始打印到3。
全屏模式 退出全屏
我们首先在一个循环之外,用 :=
语法声明并赋值一个名为 i
的变量,并将其初始化为 1
。在每次循环时打印当前的 i
值,并将 i
加 1
。当 i
达到 4
时,循环结束。
虽然在循环外面声明 i
是可以工作的,但在初始化时在循环内部声明它更常见,也更清晰。在循环开始时声明它更常见且更清晰。
// 下面的代码是一个简单的for循环,它会打印从0到2的数字。
for j := 0; j < 3; j++ {
fmt.Println(j)
}
切换到全屏,退出全屏
这个第二个循环更接近我期望的样子。变量 j
在循环内部被声明,初始值是 0
,每次迭代后增加,直到 j
达到 3
时停止。每次迭代都会打印 j
的当前值。
下面的代码是一个Go语言的例子,它使用`for`循环遍历数字范围0到2,并打印每个数字。
切换到全屏 / 退出全屏
这个循环迭代3次,i
的值分别为0、1和2。这与之前的循环实质上是一样的,只不过写得更简洁和标准。这是一个范围型循环,后续我们还会看到这种语法用于数组和切片。
以下是一个简单的 Go 代码片段,它会打印 'loop' 并立即退出循环。
for {
fmt.Println("loop")
break
}
切换到全屏 / 退出全屏
事情现在开始变得有趣了。这个循环没有设置停止条件,所以它会一直运行下去,不过我们在Println
之后立即使用break
终止它。这在你需要在任何时候根据条件退出循环时很有用。
这段代码是用来遍历一个范围从0到5的数字,如果数字是偶数,则跳过它,如果是奇数,则打印出来。
全屏模式 退出全屏
这里有个狡猾的例子。我们看到了多个新事物;包括着取模
运算符(%
),我们的第一个if
条件判断,以及continue
语句。
这个循环从 0
数到 5
,包括 0
和 5
。它利用 n % 2 == 0
判断 n
是否为偶数。如果是,则 continue
会跳过当前循环的其余部分,然后继续到下一个数字。否则,打印 n
。
简单来说,它只打印出范围内的奇数(即奇数)。
条件判断条件语句在任何编程语言中都是必不可少的,它们让我们可以根据输入变量来决定程序的分支流程。主要有两种类型的条件语句:if/else
语句和 switch
语句,让我们来了解一下它们。
if/else 语句
if
语句其实判断一个表达式,该表达式的结果要么是 true
,要么是 false
。如果表达式结果为 true
,就做某事;如果结果为 false
,则做另一件事。
再来看这个例子,我们一个一个地审视这些陈述。
如果 7 % 2 == 0 {
fmt.Println("7 是偶数。")
} else {
fmt.Println("7 是奇数。")
}
点击进入全屏模式 点击退出全屏
我们的老朋友,取模操作符,又来了。在下面这个例子中,我们检查7是否为偶数(不是),并打印出结果(它确实不是)。
if 8%4 == 0 {
fmt.Println("4 可以整除 8")
}
切换到全屏 / 退出全屏
这基本上和前面的例子一样,这说明else
部分不是必须的。
if 8%2 == 0 || 7%2 == 0 {
fmt.Println("8和7中有一个是偶数")
}
点击全屏模式 点击退出全屏
这里我们有一个 或
条件,如果你用过其他语言,这应该看起来很熟悉,让 if
语句在任一条件为真时执行
if num := 9; num < 0 {
fmt.Println(num, "是负数")
} else if num < 10 {
fmt.Println(num, "是一位数")
} else {
fmt.Println(num, "是多位数")
}
按全屏 按退出全屏
最后我们这里有一个 else if
示例。这允许我们对输入进行多个条件检查,并执行第一个为真的条件。末尾的 else
可以捕获所有未通过其他条件的任何情况。需要注意的是,变量 num
的作用域仅限于这个 if/else
块。
我不太喜欢这种在if
语句里声明变量的方法。这种方式读起来不太舒服。我们可以重写他们的例子,使其更易读,来避免这种写法。
num := 9
if num < 0 {
fmt.Println(num, "是负的")
} else if num < 10 {
fmt.Println(num, "是个一位数")
} else {
fmt.Println(num, "是多位的")
}
全屏显示 退出全屏
Go 没有 三元操作符,如果你习惯了其他语言中的三元操作符,这可能让你感到遗憾,但让我们看看我们是否真的会错过它。
开关语句(switch语句)
虽然 switch
语句类似于 if/else
块,但还是有些不同。它也依赖于评估表达式的值。但这些表达式不仅可以是 true
或 false
,还可以是任何值,并且我们还可以为每种结果设置一个 case
,并且还有一个 default
情况来捕获其他所有情况。
我们把这个例子拆开来看看,看看他们是不是偷偷加了什么新东西吧。
i := 2
fmt.Print("写 ", i, " 为 ")
switch i {
case 1:
fmt.Println("一")
case 2:
fmt.Println("二")
case 3:
fmt.Println("三")
default:
fmt.Println("其他数字")
}
点击这里全屏模式,点击这里退出全屏
首先举一个例子,已经加入了一些新东西。fmt
里的 Print
在打印时不会自动换行,我们可以用逗号分隔值,把它们拼接起来。
除了这个例子比较简单以外,定义变量 i
,判断 i
是否为 1、2 或 3,如果是则打印出相应的单词。
switch 根据今天是星期几 {
case time.Saturday, time.Sunday:
fmt.Println("今天是星期六或星期日")
default:
fmt.Println("今天是工作日,不是周末")
}
进入全屏,退出全屏
在这里,我们第一次看到time包。看起来我们在使用enum
,但因为还没学到相关内容,只能先搁置了。我们只需要知道,我们的表达式获取了当前是星期几,并使用了case
,用逗号分隔来像or
运算符那样起作用,我们检查是否是周末或平时工作日。
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("现在还不到中午")
default:
fmt.Println("现在已经过了中午")
}
全屏模式切换 退出全屏
这个例子与之前的例子类似,只是我们将 time.Now()
的调用结果存储为一个变量,并且没有将表达式传递给 switch
。这将条件检查移至各个 case 语句中,使其行为类似于 if/else
语句的行为,其中第一个为 true
的 case 将被执行。
whatAmI := func(i interface{}) {
switch t := i.(type) {
case bool:
fmt.Println("我是一个布尔值")
case int:
fmt.Println("我是一个整数")
default:
fmt.Printf("不知道这是什么类型 %T\n", t)
}
}
whatAmI(true)
whatAmI(1)
whatAmI("嘿")
全屏 | 退出全屏
好的,我猜他们可能会偷偷加入一些额外的东西,果然如此,这里就有了我们第一个可重用的函数,一个叫接口
的东西(这个我也不太清楚)和一个Printf
函数。
让我们一步步来,弄清楚这是在说啥。首先,我们有一个叫做 whatAmI
的函数,它接受一个 interface{}
类型的参数 i
。
我不太清楚interface{}
是什么意思,所以我快速查了一下。看起来interface
是我们稍后会学到的内容,但interface{}
是用来告诉Go我们不知道传递给函数的是什么类型。可以把interface{}
想象成一个占位符,它可以容纳任何类型的数据。也就是说,i
可以是任何东西。
接下来是我们的 switch 表达式,我们声明了一个新的变量 t
并让它存储 i
的类型。这使我们可以根据需要的类型来编写 case
。
我们有两个case
和一个default
备用。前两个case
分别检查i
是否为bool
(true
或false
)或是否为int
(整数),如果不是这两种情况,备用会使用Printf
输出其类型。Printf
允许格式化输出,其中%T
会打印变量的类型。我们在这里使用Printf
是因为%T
不能直接转换为字符串。我们还需要以\n
结尾来添加换行符。
运行 Go 应用程序的一个好方法是将其 打包成 Docker 镜像,这使得它们可以在包括 Windows、Linux 和 macOS 在内的不同系统上轻松移植。我们将使用 多阶段 Dockerfile 来高效构建和运行我们的 Go 程序。
(点击以查看Docker标志)
为什么使用多阶段构建的Dockerfile?
多阶段构建能帮助我们使最终镜像更小更高效,通过将构建环境与运行时环境分离开来。这减少不必要的依赖项,让最终镜像更干净,从而提升安全性和性能。
让我们先写一个 Dockerfile
。
# 构建 GO 二进制程序
FROM golang:1.24.1-alpine AS build
COPY ./main.go ./main.go
RUN go build -o /bin/output ./main.go
# 运行 GO 二进制程序
FROM scratch:
COPY --from=build /bin/output /bin/output
CMD ["/bin/output"]
# 构建阶段:从 Alpine 版本的 Go 1.24.1 开始
进入全屏,退出全屏
构建步骤
我们从官方的golang:1.24.1-alpine镜像起步。我们将main.go
文件复制到容器里(你可以重命名这个文件,如果需要的话),然后将其编译成可执行文件并放置在/bin/output
。
运行时
运行时阶段使用 FROM scratch
,这意味着它没有任何基础操作系统。scratch
是一个空的镜像,不包含任何其他内容。这将最小化最终镜像的大小。我们使用 COPY --from=build
命令,该命令仅从构建阶段高效复制编译后的二进制文件,并将 CMD 设置为 ["/bin/output"]
作为入口命令。
构建并运行Docker容器
要构建并运行该镜像,可以使用以下命令:
请注意在命令前加上适当的提示符号,如“$”或“>”。
# 构建镜像(比如使用 `docker build` 命令,`.` 表示当前目录)
docker build -t my-go-app:latest .
# 运行容器(比如使用 `docker run` 命令)
docker run my-go-app:latest
全屏 退出全屏
结束啦这次我们已经涵盖了非常多的内容,我们的程序正变得越来越高级。我们正在顺利地前进,而且语法使用起来非常简单。下次我们将看看数组、切片和映射。我们确实取得了一些进展,但是,但我们才刚刚开始了解皮毛。
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章