Go 语言 for 的用法

For statements

本文简单翻译了 Go 语言中 for 的三种用法,可快速学习 Go 语言 for 的使用方法,希望本文能为你解开一些关于 for 的疑惑。详细内容可见文档 For statements

For statements with single condition

在最简单的形式中,只要 for 语句布尔条件结果为真,就重复执行代码块。在每次迭代之前都会评估该条件。如果条件不存在,则相当于布尔值 true。

for a < b {
	a *= 2
}

// 永远为真
for { }

For statements with for clause

带有 ForClause 的 for 语句也受其条件控制,但此外它还可以指定一个 init 和一个 post 语句,例如一个赋值语句、一个递增或递减语句。init 语句可以是一个短变量声明,但 post 语句不行。init 语句声明的变量的作用域在 for 代码块内部。

for i := 0; i < 10; i++ {
	f(i)
}

// 不能在外面使用变量 i

如果 init 语句不为空,则在第一次评估迭代条件前执行一次;post 语句在每次执行代码块后执行。ForClause 的任何元素都可以为空,但除非只有一个条件,否则分号不能省略。如果条件不存在,则相当于布尔值 true。

这种形式的 for 语句与 C++ 的 for 循环很相似。但有一点要注意的是,它只能有一个 post 语句,并且在 Go 中递增和递减是语句,这意味着我们不能在 post 语句中写出 i++, j-- 这样的代码。

例如,我们想验证一个字符串是否是回文串,用 C++ 可以这样写:

bool judge(string str) {
    for (int i = 0, j = str.size()-1; i < j; i++, j--) {
        if (str[i] != str[j]) {
            return false;
        }
    }
    return true;
}

在 Go 中,我们需要写成如下形式:

func judge(str string) bool {
    for i, j := 0, len(str)-1; i < j; {
        if str[i] != str[j] {
            return false
        }
        i++
        j--
    }
    return true
}

For statements with range clause

带有 range 子句的 for 语句会遍历数组、切片、字符串或 map 的所有条目,或者从 channel 接收的值。对于每个条目,它会将迭代值分配给相应的迭代变量(如果存在),然后执行代码块。

RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .

range 子句中右边的表达式称为范围表达式,其类型必须是数组、数组指针、切片、字符串、map 或允许接收操作的 channel。与赋值类似,左侧的操作数必须可寻址的或 map 索引表达式;它们表示迭代变量。如果范围表达式是 channel,则最多允许一个迭代变量,否则最多允许两个。

左侧的函数调用每次迭代都会计算一次。对于迭代,如果存在相应的迭代变量,则按如下方式生成迭代值:

范围表达式                            第一个值及类型   第二个值及类型

array or slice  a [n]E, *[n]E or []E index    int    a[i]       E
string          s string type        index    int    见下文      rune
map             m map[K]V            key      K      m[k]       V
channel         c chan E, <-chan E   element  E
  1. 对于数组、数组指针或切片值 a,索引迭代值从 0 开始按递增顺序生成。如果只有一个迭代变量,则只会生成从 0 到 len(a)-1 的整数值,并不会索引到数组或切片本身
  2. 对于字符串值,range 子句从 0 开始迭代字符串中的 Unicode 码点。在连续的迭代中,索引值将是字符串中连续 UTF-8-encoded 码点的第一个字节的索引;而第二个值,类型为 rune,是相应码点的值

UTF8 解码

  1. map 的迭代顺序未指定(底层实现是哈希表),并且不保证两次迭代的顺序相同
  2. 对于 channel,产生的迭代值是 channel 发送的连续值,直到 channel 关闭

迭代值被分配给各自的迭代变量,如赋值语句中一样。迭代变量可以通过 range 子句使用短变量声明(:=)的形式来声明。

需要注意的是对 string 的遍历,它并不是一个字节一个字节遍历的,它是以 Unicode 码点为单位遍历的。string 使用 UTF8 编码,使用 1 到 4 个字节来表示每个 Unicode 码点,ASCII 部分字符只使用 1 个字节,常用字符部分使用 2 或 3 个字节表示。

上面图片可以看到中文占了三个字节,图片出处为《Go 程序设计语言》第三章

str := "Hello, 世界"
for i, r := range str {
    fmt.Printf("%d\t%q\n", i, r)
}

var key string
var val int
m := map[string]int{"mon": 0, "tue": 1, "wed": 2, "thu": 3, "fri": 4, "sat": 5, "sun": 6}
for key, val = range m {
    fmt.Println(key, " : ", val)
}
<think>好的,我现在需要帮用户解决关于Go语言for循环用法的问题。用户已经提供了一些参考资料,我需要整理这些信息并生成清晰的回答。首先,我得仔细阅读用户提供的四个引用,理解每个引用的内容,然后归纳出for循环的不同用法和示例。 首先看引用[1],里面提到Go语言for循环经典语法是表达式1、表达式2、表达式3的结构,类似于传统的for循环,例如for i := 0; i < 5; i++。还提到for循环常用于遍历数组或切片。这一点很重要,是基本用法。 接下来是引用[2],这里指出forGo中唯一的循环关键字,但有四种用法:变量迭代(传统for)、条件循环(类似while)、死循环(loop)、数组迭代(foreach)。需要将这四种用法分别解释清楚,并给出例子。 引用[3]中的代码示例详细展示了四种情况:标准for循环、类似while的循环、无限循环使用break退出,以及continue的用法。这些具体的代码可以帮助用户理解不同场景下的应用,特别是条件循环和无限循环的处理方式。 引用[4]则展示了同一for循环中使用多个初始变量和自增变量的情况,比如字符串反转的例子。这里需要注意,自增变量不能用++或--,而是需要显式赋值,例如i, j = i+1, j-1。这一点可能容易出错,需要特别说明。 现在需要将这四个引用的信息整合成一个结构清晰的回答。根据用户提供的示例结构,应该先概述for循环的四种用法,然后分点详细说明每种用法,并附上代码示例。最后生成相关问题。 需要注意用户提到的系统级指令,比如数学表达式要用$...$,但这里的问题是关于编程的,可能不涉及数学公式,所以可能不需要处理这点。另外,回答必须使用中文,代码块用正确格式,引用标识要自然添加在引用的段落末尾。 接下来整理结构: 1. 传统for循环:初始化变量、条件判断、后续操作,示例代码。 2. 条件循环(类似while):省略初始化和后续,只保留条件,示例。 3. 无限循环:省略所有表达式,用break退出,示例。 4. 数组/切片遍历:使用range关键字,示例。 5. 多变量操作:同时初始化i和j,每次循环调整两个变量,示例。 每个部分需要引用对应的引用来源,例如在传统for循环后加[^1][^3],在条件循环加[^2][^3]等。 然后检查是否有遗漏,比如continue的用法在引用[3]中有示例,可能需要单独提一下,但用户的问题主要是for用法,所以可能放在continue部分作为补充。 最后生成相关问题,参考用户示例中的相关问题,比如性能优化、不同用法的区别、注意事项等。 现在需要确保所有引用都被正确标注,没有遗漏。比如引用[4]中的多变量用法要在对应部分提到,并加上[^4]。 在写作时要注意用自然的中文,分步骤说明,代码示例正确,格式正确。此外,用户要求结构清晰,帮助用户逐步解决问题,因此每个用法分点列出,代码用代码块包裹,语言标记为go。</think>### Go语言for循环用法详解 Go语言的`for`循环是**唯一**的循环结构,支持多种编程范式。通过不同语法形式可以实现传统循环、条件循环、无限循环和集合遍历等功能[^2]。 --- #### 一、传统for循环 **语法格式**: ```go for 初始化语句; 条件判断; 后续操作 { // 循环体 } ``` **示例**: ```go for i := 0; i < 5; i++ { fmt.Printf("第%d次循环\n", i+1) } ``` - 初始化语句:`i := 0` - 条件判断:`i < 5` - 后续操作:`i++` 用途:适用于已知循环次数的场景[^1][^3]。 --- #### 二、条件循环(类似while) **语法格式**: ```go for 条件判断 { // 循环体 } ``` **示例**: ```go count := 0 for count < 3 { fmt.Printf("count: %d\n", count) count++ } ``` 用途:当循环次数不确定时,通过条件控制循环[^3]。 --- #### 三、无限循环 **语法格式**: ```go for { // 循环体(需手动退出) } ``` **示例**: ```go sum := 0 for { sum++ if sum > 3 { break // 通过break退出循环[^3] } fmt.Printf("sum: %d\n", sum) } ``` --- #### 四、遍历数组/切片(类似foreach) **语法格式**: ```go for 索引, 值 := range 集合 { // 循环体 } ``` **示例**: ```go arr := []int{10, 20, 30} for index, value := range arr { fmt.Printf("索引:%d, 值:%d\n", index, value) } ``` - 若不需要索引,可用`_`占位:`for _, value := range arr`[^3]。 --- #### 五、多变量操作 **语法特性**: - 支持同时初始化多个变量 - 自增操作需显式赋值,不能使用`++`或`--`简写[^4] **示例**(字符串反转): ```go func Reverse(s string) string { b := []byte(s) for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] // 交换变量 } return string(b) } ``` --- #### 六、控制语句 1. **`break`**:强制退出当前循环 2. **`continue`**:跳过本次循环,进入下一次 ```go for i := 1; i <= 5; i++ { if i%2 == 0 { continue // 跳过偶数[^3] } fmt.Printf("奇数: %d\n", i) } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值