Golang这段代码有什么问题?

Golang这段代码有什么问题? https://play.golang.org/p/lVgxVaeL8Jp

19 回复

一个都不行!!!

更多关于Golang这段代码有什么问题?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,有什么地方让你感到困惑吗?

你能告诉我你从哪里开始遇到困难吗?我可以更好地解释。

编译器明确指出了问题所在。这三条信息中哪一条你不理解?

这很有意思。我之前没有接触过您提供的信息,正在尝试实验。

好的,我会逐步处理。首先,"declares"在这里的定义是什么?

当你修复了所有问题后,仍然会遇到将 x(整数类型)与 false 进行比较的问题。这不是合法的运算,会导致类型不匹配:int 类型与 bool 类型不兼容。

这非常有帮助。我尝试修正了我的错误并得到了这个: https://play.golang.org/p/UwJWHt17sYV

我大概能理解您说的部分内容,但并非全部。我明白自己不该做那些事,但其他内容就不太明白了。(顺便说一句,其实我自己也不清楚当时具体做了什么😂。只是随便试试而已)

我觉得自己就像个正在学说话的婴儿。所有的语言都涌向我,但我却无法理解。我没有任何编程背景。

那么首先,这是什么意思?err := strconv.Atoi(“42”); err == nil

err := strconv.Atoi("42"); err == nil

我应该在何处尝试 if i, err := strconv.Atoi(“42”); err == nil { /* 语句 */ } 我将其理解为…

package main

import (
	"fmt"
	"strconv"
)

func main() {
	if i, err := strconv.Atoi("42"); err == nil {
		fmt.Printf("i = %+v\n", i)
		fmt.Printf("err = %+v\n", err)
	}
}

感谢您的鼓励。虽然我在学习Go语言方面还是个新手,但这并不让我感到沮丧,反而让我感到兴奋和有趣!这比在电视上看足球比赛还要棒!

  1. if 语句中缺少条件

if x == 2; 中多了一个分号。如果只需要条件判断(而不是赋值和测试),在左括号前不需要分号。

  1. 期望分号或换行符,却出现了意外的 !

if x !false 不是检查不等式的正确方式。正确的做法是使用 if x != false

  1. 期望逗号或 ),却出现了意外的换行符

fmt.Println("neither" 处缺少右括号。

func main() {
    fmt.Println("hello world")
}

正如 Hatnice 所说,你的比较中存在类型不匹配的问题。

另外,为了澄清你之前遇到的第一个错误,在 if 语句中使用分号可以执行如下操作:

func main() {
    if i, err := strconv.Atoi("42"); err == nil {
		fmt.Printf("%d\n", i+1) //将输出43
	} else {
		fmt.Println(err)
	}
	
	if i, err := strconv.Atoi("42dwcdc"); err == nil {
		fmt.Printf("%d\n", i+1)
	} else {
		fmt.Println(err) //将输出错误信息
	}
}

当你只是测试条件时,比如 x == 2,使用分号会导致语法错误。

请注意,在这种情况下,ierr 的作用域仅限于 if-else 块内,而不是 main 函数。这就是为什么可以多次声明它们,以及如果你稍后在 main 函数中使用它们会报错的原因,例如如果你尝试执行 fmt.Println(i),会得到 undefined: i 的错误。

查看 Go 语言指南中的 If 部分(请查看此页及后续两页):https://tour.golang.org/flowcontrol/5

你可以想象自己正在与Go编译器对话。它只是一台机器,你需要对所有事情都非常具体,并且要精确使用它的语言。

Go是一种要求每个变量都有特定类型的语言。由于编译器需要知道你希望变量是什么类型,你自然需要告诉它。你可以通过声明变量来实现这一点。以下是一个简单的示例,类似于你已经见过和使用过的:

var abc int

这个声明告诉编译器你正在使用一个名为abc的变量,并且它是一个整数(实际上是int类型),而不是其他类型(比如字符串、浮点数、切片、符文等等)。既然Go编译器知道了这一点,如果你犯了一个错误,尝试将abc设置为另一种类型,或者将其用作整数以外的其他东西,它会告诉你犯了一个错误。

我认为这对于刚开始学习编程的人来说一定显得非常复杂。也许你会问:“为什么它要设计得如此复杂和困难?” 答案是,你必须考虑在一个无类型语言中编写一个数千(甚至数十万)行长的程序是什么样子,然后得到一个似乎告诉你2 + 3"不是一个数字"的错误!然后你必须分析你(或其他人)的代码,看看在哪里一个变量被用作整数,而实际上它包含的是字符串或其他非整数的内容。在大型程序中,这很困难且不有趣!Go的编译器不会默默地允许你自掘坟墓,而是在编译期间捕获类型不匹配。然后你可以快速轻松地修复问题,并继续创建你的程序,这要容易得多,也更有趣。我希望这能有所帮助。

关于类型不匹配的问题…

x := 2 这行代码声明了 x 并将其设置为 2,这是一个整数。因此 x 是一个 int 类型的变量。该语句等价于:

var x int = 2

但随后你尝试将其与 false 进行比较,而 falsebool 类型。在 Go 语言中,你不能将整数设置为 truefalse,也不能将 bool 变量设置为整数,比如 273452。而且你也不能使用 ==!= 等运算符来比较它们,因为 truefalse 没有对应的整数值。(即使你可能倾向于认为它们类似于 1 和 0。)

(在其他语言中,比如 C 语言,你可以这样做,因为非零整数被视为"真"。但 Go 不允许这样做。)

有时候你可能需要比较不同类型的值,或者将一个类型的变量设置为另一个类型的值。为此,可以将一种类型转换为另一种类型。

例如:

var int_number int = 73
var float_number float32

float_number = float32(int_number)

float_number 设置为 73.0。(如果直接写 float_number = int_number 会导致错误。)要进行转换,请将数据类型当作函数使用,并将要转换的变量作为其参数。

但在你展示的情况下,将 bool 转换为 int 没有意义,所以 int(x) 不会起作用。

希望这能帮助你更好地理解这些内容。

关于代码片段,你没有理解完整内容。试试这个:

if i, err := strconv.Atoi("42"); err == nil { /* statements */ }

这是更复杂的if/then结构示例。它等同于:

i, err := strconv.Atoi("42")
if err == nil { /* statements */ }

Go允许在if语句的布尔表达式前插入一个语句。这只是为了让代码更简洁。(个人认为,除非是非常简单的情况,最好避免使用它。)

需要澄清的是,这两者并不完全等同。正如我在之前的帖子中所述,在if语句中声明和赋值时,变量的作用域仅限于if块内,而非外围函数。因此,在第一种情况下,在if(或if-else if-else)作用域之后尝试使用这些变量是错误的,例如:

func someFunc() {
  if i, err := strconv.Atoi("42"); err == nil { 
    /* 
     这里可以写一些语句。
     这里可以使用i和err。
   */ 
  } else {
   // 这里i和err也可以正常使用,这仍然属于if作用域。
  }
  fmt.Println(err) //错误,err未在此作用域内声明,这将无法编译。
}

在第二种情况下,变量的作用域将是函数级别,所以这样写没问题:

func someFunc() {
  i, err := strconv.Atoi("42")
  if err == nil { /* statements */ }
  fmt.Println(err) //这样写没问题,err在这里已正确定义。
}

这一点在Go教程中我之前链接的章节有详细说明。

cherilexvold1974:

我觉得自己就像个学说话的婴儿。所有语言都向我涌来,但我完全听不懂。我没有任何编程背景。 那么首先,这个是什么意思?err := strconv.Atoi(“42”); err == nil

多年前我曾尝试学习一点日语,第一部分就是要学会写平假名字母。我也有同样的感觉!我必须反复练习书写每个字符。感觉自己就像个五岁小孩,刚刚开始学写字。

幸运的是,任何编程语言都比日语容易学得多。所以不用担心。

关于那段代码片段,你没有看到完整的内容。试试这个:

if i, err := strconv.Atoi("42"); err == nil { /* statements */ }

这是一个更复杂的if/then结构的例子。它等同于:

i, err := strconv.Atoi("42")
if err == nil { /* statements */ }

Go语言允许你在if语句的布尔表达式之前插入一个语句。这只是为了让代码更简洁。(个人认为,除非是非常简单的情况,最好避免使用它。)

第一行是这样的:

x, y = 1, 2

这会将x设为1y设为2。这被称为元组赋值。它几乎等同于:

x = 1
y = 2

但是当你有返回多个值的函数时,你必须使用元组赋值将这些值存储到变量中。所以:

i, err := strconv.Atoi("42")

结果是字符串"42"被转换成int并存储在i中,如果Atoi()遇到问题,err将不是nil。良好的编程实践是始终(或至少通常)检查错误并处理它们。

这是你需要的解释吗?

这段代码存在几个关键问题,主要涉及并发安全和切片操作的正确性。以下是具体分析和修复方案:

问题1:并发写入map导致的竞态条件

// 原代码问题
go func() {
    for i := 0; i < 5; i++ {
        m[i] = i // 并发写入,不安全
    }
}()

修复方案:使用sync.Mutex

var mu sync.Mutex
go func() {
    for i := 0; i < 5; i++ {
        mu.Lock()
        m[i] = i
        mu.Unlock()
    }
}()

问题2:切片越界访问

// 原代码问题
s := make([]int, 0, 10)
s[5] = 5 // 索引5超出长度0的边界

修复方案1:预分配长度

s := make([]int, 10) // 长度和容量都是10
s[5] = 5 // 安全

方案2:使用append

s := make([]int, 0, 10)
s = append(s, 5) // 安全添加

完整修复代码示例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    m := make(map[int]int)
    var mu sync.Mutex
    var wg sync.WaitGroup
    
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            mu.Lock()
            m[i] = i
            mu.Unlock()
        }
    }()
    
    s := make([]int, 10)
    for i := 0; i < 5; i++ {
        s[i] = i
    }
    
    wg.Wait()
    fmt.Println("Map:", m)
    fmt.Println("Slice:", s)
}

主要修复点:

  1. 使用互斥锁保护map的并发写入
  2. 修正切片初始化方式,避免越界访问
  3. 添加WaitGroup确保goroutine执行完成
回到顶部