찾다
백엔드 개발GolangGo 루프 탐색의 함정을 기록하세요.

튜토리얼 칼럼에서는 GO의 루프를 통해 작은 구덩이를 사용하는 방법을 공유할 예정이니, 필요한 친구들에게 도움이 되길 바랍니다!

Go 루프 탐색의 함정을 기록하세요.Golang의 프로세스 제어에는 for와 range라는 두 가지 유형의 루프 문이 있습니다.

for 문

1. 대입식, 관계식 또는 논리식, 대입식 { }
for i := 0; i 
2. 관계식 또는 논리식 수식 { } code>

n := 10for n > 0 {
 n--}

3.for { }1.for 赋值表达式; 关系表达式或逻辑表达式; 赋值表达式 { }

for {
 fmt.Println("hello world")
}
// 等价于
// for true {
//     fmt.Println("hello world")
// }

2.for 关系表达式或逻辑表达式 { }

str := "abc"
for i, char := range str {
    fmt.Printf("%d => %s\n", i, string(char))
}
for i := range str { //只有一个返回值
    fmt.Printf("%d\n", i)
}
nums := []int{1, 2, 3}
for i, num := range nums {
    fmt.Printf("%d => %d\n", i, num)
}
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
    fmt.Printf("%s => %s\n", k, v)
}
for k := range kvs { //只有一个返回值
    fmt.Printf("%s\n", k)
}
// 输出结果
// 0 => a
// 1 => b
// 2 => c
// 0
// 1
// 2
// 0 => 1
// 1 => 2
// 2 => 3
// a => apple
// b => banana
// a
// b

3.for { }

func main() {
    var out []*int
    for i := 0; i < 3; i++ {
        // i := i
        out = append(out, &i)
    }
    fmt.Println("值:", *out[0], *out[1], *out[2])
    fmt.Println("地址:", out[0], out[1], out[2])
}
// 输出结果
// 值: 3 3 3
// 地址: 0xc000012090 0xc000012090 0xc000012090

range语句

Golang range类似迭代器操作,可以对 slice、map、数组、字符串等进行迭代循环。在字符串、数组和切片中它返回 (索引, 值) ,在集合中返回 (键, 值),但若当只有一个返回值时,第一个参数是索引或键。

func main() {
    a1 := []int{1, 2, 3}
    a2 := make([]*int, len(a1))

    for i, v := range a1 {
        a2[i] = &v
    }

    fmt.Println("值:", *a2[0], *a2[1], *a2[2])
    fmt.Println("地址:", a2[0], a2[1], a2[2])
}
// 输出结果
// 值: 3 3 3
// 地址: 0xc000012090 0xc000012090 0xc000012090

for循环尤其是range语句,在平时开发过程中频繁使用,但很多开发者(本人算一个)经常会在以下场景中踩坑。

场景一,使用循环迭代器的变量

先来看一个明显的错误:

func main() {
    var out [][]int
    for _, i := range [][1]int{{1}, {2}, {3}} {
        out = append(out, i[:])
    }
    fmt.Println("Values:", out)}// 输出结果// [[3] [3] [3]]

分析

out是一个整型指针数组变量,在for循环中,声明了一个i变量,每次循环将i的地址追加到out切片中,但是每次追加的其实都是i变量,因此我们追加的是一个相同的地址,而该地址最终的值是3。

正确做法

解开代码中的注释// i := i,每次循环时都重新创建一个新的i变量。


再看一个比较隐秘的错误:

func main() {
    values := []int{1, 2, 3}
    wg := sync.WaitGroup{}
    for _, val := range values {
        wg.Add(1)
        go func() {
            fmt.Println(val)
            wg.Done()
        }()
    }
    wg.Wait()}// 输出结果// 3// 3// 3

分析

大多数人就是在range这里给变量赋值的时候踩坑,因为比较隐秘,其实情况和上面的一样,range在遍历值类型时,其中的v是一个局部变量,只会声明初始化一次,之后每次循环时重新赋值覆盖前面的,所以给a2[i]赋值的时候其实都是同一个地址&v,而v最终的值为a1最后一个元素的值,也就是3。

正确做法

a2[i]赋值时传递原始指针,即a2[i] = &a1[i]
②创建临时变量t := va2[i] = &t
③闭包(与②原理一样),func(v int) { a2[i] = &v }(v)


更为隐秘的还有:

for _, val := range values {
    wg.Add(1)
    val := val    go func() {
        fmt.Println(val)
        wg.Done()
    }()}

原理也是一样的,不论遍历多少次,i[:]总是被本次遍历的值所覆盖

场景二,在循环体内使用goroutines

for _, val := range values {
    wg.Add(1)
    go func(val int) {
        fmt.Println(val)
        wg.Done()
    }(val)}

分析

对于主协程来讲,循环是很快就跑完的,而这个时候各个协程可能才开始跑,此时val的值已经遍历到最后一个了,所以各协程都输出了3。(如果遍历数据庞大,主协程遍历耗时较久的话,goroutine的输出会根据当时候的valrrreee

range 문

Golang 범위는 반복자 작업과 유사하며 슬라이스, 맵, 배열, 문자열 등을 반복할 수 있습니다. 문자열, 배열 및 슬라이스에서는 (인덱스, 값)을 반환하고 컬렉션에서는 (키, 값)을 반환하지만 반환 값이 하나만 있는 경우 첫 번째 인수는 인덱스 또는 키입니다.

rrreee
for 루프, 특히 range 문은 일상적인 개발 과정에서 자주 사용되지만, 저를 포함한 많은 개발자들은 다음과 같은 시나리오에서 실수를 자주 저지릅니다.

시나리오 1, 루프 반복기의 변수 사용🎜🎜먼저 명백한 오류를 살펴보겠습니다. 🎜rrreee🎜🎜Analytic🎜🎜🎜out은 for에서 정수 포인터 배열 변수입니다. loop 에서는 i 변수가 선언되고 각 루프는 i의 주소를 out 슬라이스에 추가하지만 매번 추가되는 것은 실제로는 i 변수이므로 동일한 주소를 추가하고 주소의 최종 값은 3입니다. 🎜🎜🎜올바른 접근 방식🎜🎜🎜코드에서 // i := i 주석을 잠금 해제하고 반복될 때마다 새 i 변수를 다시 만듭니다. 🎜
🎜좀 더 비밀스러운 실수를 살펴보겠습니다: 🎜rrreee🎜🎜Analytics🎜🎜🎜대부분의 사람들은 여기 범위의 변수에 값을 할당할 때 실수를 합니다. 사실 상황은 위와 같습니다. range가 값 유형을 순회할 때 v는 지역 변수이며 한 번만 선언되고 초기화된 후 다시 할당됩니다. 이전 항목을 덮어쓰기 위해 반복할 때마다 a2[i]에 값을 할당할 때 실제로는 모두 동일한 주소 &v를 가지며 최종 값을 갖습니다. va1입니다. 마지막 요소의 값은 3입니다. 🎜🎜🎜올바른 접근 방식🎜🎜🎜1a2[i] 할당 시 원래 포인터를 전달합니다. 즉, a2[i] = &a1[i]
②임시 변수 t := v 생성 a2[i] = &t
③ 클로저(2번과 같은 원리), func(v int) { a2 [i] = &v }(v)🎜
🎜더 비밀스러운 점은: 🎜rrreee🎜원칙은 동일합니다. 몇 번을 탐색하더라도 i[ :] 항상 이 순회 값으로 덮어쓰기🎜🎜🎜🎜시나리오 2, goroutines 사용🎜rrreee🎜🎜analytic🎜🎜🎜메인 코루틴의 경우 루프는 빠르게 실행되며 이때 각 코루틴은 방금 실행을 시작했습니다. 이때 val의 값은 마지막 값으로 순회되었으므로 각 코루틴은 3을 출력합니다. (순회 데이터가 크고 메인 코루틴 순회 시간이 오래 걸리는 경우, 고루틴의 출력은 그때의 val 값을 기준으로 하게 되므로 출력 결과가 동일하지 않을 수 있습니다. 매번.) 🎜🎜🎜 해결책🎜🎜🎜①임시 변수를 사용하세요🎜rrreee🎜②클로저를 사용하세요🎜rrreee

위 내용은 Go 루프 탐색의 함정을 기록하세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 learnku에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
Golang : Go 프로그래밍 언어가 설명되었습니다Golang : Go 프로그래밍 언어가 설명되었습니다Apr 10, 2025 am 11:18 AM

GO의 핵심 기능에는 쓰레기 수집, 정적 연결 및 동시성 지원이 포함됩니다. 1. Go Language의 동시성 모델은 고루틴 및 채널을 통한 효율적인 동시 프로그래밍을 실현합니다. 2. 인터페이스 및 다형성은 인터페이스 방법을 통해 구현되므로 서로 다른 유형을 통일 된 방식으로 처리 할 수 ​​있습니다. 3. 기본 사용법은 기능 정의 및 호출의 효율성을 보여줍니다. 4. 고급 사용에서 슬라이스는 동적 크기 조정의 강력한 기능을 제공합니다. 5. 레이스 조건과 같은 일반적인 오류는 Getest-race를 통해 감지 및 해결할 수 있습니다. 6. 성능 최적화는 sync.pool을 통해 개체를 재사용하여 쓰레기 수집 압력을 줄입니다.

Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Apr 09, 2025 pm 05:17 PM

Go Language는 효율적이고 확장 가능한 시스템을 구축하는 데 잘 작동합니다. 장점은 다음과 같습니다. 1. 고성능 : 기계 코드로 컴파일, 빠른 달리기 속도; 2. 동시 프로그래밍 : 고어 라틴 및 채널을 통한 멀티 태스킹 단순화; 3. 단순성 : 간결한 구문, 학습 및 유지 보수 비용 절감; 4. 크로스 플랫폼 : 크로스 플랫폼 컴파일, 쉬운 배포를 지원합니다.

SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?Apr 02, 2025 pm 05:24 PM

SQL 쿼리 결과의 정렬에 대해 혼란스러워합니다. SQL을 학습하는 과정에서 종종 혼란스러운 문제가 발생합니다. 최근 저자는 "Mick-SQL 기본 사항"을 읽고 있습니다.

기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?Apr 02, 2025 pm 05:21 PM

기술 스택 컨버전스와 기술 선택의 관계, 소프트웨어 개발에서 기술 스택의 선택 및 관리는 매우 중요한 문제입니다. 최근에 일부 독자들은 ...

반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?Apr 02, 2025 pm 05:15 PM

GO 언어로 세 가지 구조를 비교하고 처리하는 방법. GO 프로그래밍에서는 때때로 두 구조의 차이점을 비교하고 이러한 차이점을 ...에 적용해야합니다.

GO에서 전 세계적으로 설치된 패키지를 보는 방법?GO에서 전 세계적으로 설치된 패키지를 보는 방법?Apr 02, 2025 pm 05:12 PM

GO에서 전 세계적으로 설치된 패키지를 보는 방법? Go Language로 발전하는 과정에서 Go는 종종 사용합니다 ...

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까?골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까?Apr 02, 2025 pm 05:09 PM

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Go Language 개발을 위해 Goland를 사용할 때 많은 개발자가 사용자 정의 구조 태그를 만날 것입니다 ...

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.