来自一位国外前端程序员学习go语言的第二天

2023-06-01 00:00:00 程序员 国外 第二天

主人公Magda Rosłaniec是一位来自波兰苏瓦基的前端开发人员,

我在网上看到她的文章我觉得很有意思,所以记录顺便复习一下里面的go基础知识


正文:

我宁愿给它命名——第 2 部分而不是第 2 天,因为我在一天内学会了所有这些东西,

但我花了 4 天时间来写这些笔记,但它们仍然不完整。 但写作也是学习的一部分。


1. for 循环和 if 语句

for 循环和 if 语句使用起来非常简单。 

但是要正确使用它们,我们需要了解两件事:块和作用域。


什么是块?

Go 中的代码可以分为称为块的段。 块通常是大括号之间的代码部分。 

它们可以嵌套。 当我们创建一个 for 循环时,大括号之间的所有内容都是一个块。 

如果我们将 if 语句放在 for 循环中,则胡子(大括号)括号之间的代码的每一部分都会创建一个块。

for num := 1; num <= 10; num++ {
    if num % 2 == 0 {
        fmt.Println(num, "is an even number.")
    } else if num % 2 != 0 {
    fmt.Println(num, "is an odd number.")
    }
}

所以上面的例子中有3个代码块。


范围是多少?

变量的范围与块相连。 当我们声明一个变量时,它只能在我们声明它的块内被识别,并且块嵌套在该块内。 因此,当我们在 if 语句的一部分内声明变量时,它不会在 if 语句的另一部分以及 if-else 子句之外起作用。


如果我想稍微更改之前的代码并添加一个名为 answer 的变量,如下所示:

for num := 1; num <= 10; num++ {        
    if num %2 == 0 {
        answer := "is an even number."
    } else if num%2 != 0 {
    answer := "is an odd number."       
    }       
    fmt.Println(num, answer)
}

去不让我做。 对于前两个“答案”,它将告诉变量已声明且从未使用过。 

对于最后一个“答案”,它会说这是一个未声明的名称。


要修复它,我需要在第一个块中声明 answer 变量 - for 循环 

- 就像这样:

for num := 1; num <= 10; num++ {    
    var answer string   
    if num %2 == 0 {
    answer = "is an even number."
    } else if num%2 != 0 {
    answer = "is an odd number."        
    }       
    fmt.Println(num, answer)
}


什么是继续和中断?

有时我们想在满足特定条件时结束循环。 因此,我们使用 break 语句。

假设我们要在 1 到 10(包括 10)的范围内寻找一个除以 5 的数字。 

我们对我们得到的第一个数字感到满意。

for n := 1; n <= 10;n++ {       
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
    break
    } else {
    fmt.Println(n, "is not divided by 5")
    }
}

这个简短的程序只会运行,只要它涉及到第一个可以被五除的数字:5。

运行这个循环后(当然,它应该放在函数中以使其在 Go 中工作)我们将看到这样的输出:

1 is not divided by 5
2 is not divided by 5
3 is not divided by 5
4 is not divided by 5
5 is divided by 5

正如我们所看到的,我的程序在检查范围内的所有数字之前停止了。


Continue 不会停止循环,但是如果我们在该语句的块中 continue 之后有一些东西,

它不会检查代码,只会立即进入循环的下一次迭代。

for n := 1; n <= 10;n++ {       
    if n % 5 == 0 {
        fmt.Println(n, "is divided by 5")
    continue
        if (n == 5) {
        fmt.Println("It's 5.")
    }
    } else {
        fmt.Println(n, "is not divided by 5")
    }
}
//输出
1 is not divided by 5
2 is not divided by 5
3 is not divided by 5
4 is not divided by 5
5 is divided by 5
6 is not divided by 5
7 is not divided by 5
8 is not divided by 5
9 is not divided by 5
10 is divided by 5

输出显示 continue 之后的块根本没有执行。


2.什么都有一个包

到目前为止,我还没有在 Go 中使用过很多方法,

但注意到要使用 Go 提供的几乎所有功能和方法,我首先需要导入包含它们的包。

如果我想打印输出,我需要 fmt 库,然后是 Print() 函数之一。 

如果我想修剪下一行字符,我需要 strings 包和 TrimSpace() 函数。

但是当我们想要使用连接到某种类型的值的方法时,事情变得有点复杂了。


例如,当我们想从日期中只获取一年时,我们首先必须导入时间包。 

然后我们将使用需要分配给变量的 Now() 函数访问日期。 

只有这样我们才会使用称为 Year() 的方法。

package main 

import (
    "fmt"
    "time"
)

func main() {
    var now time.Time = time.Now();
    var year int = now.Year()   
    fmt.Println(year)   
}

在该函数中,第一个(现在)变量的类型是 time.Time。

第二个(年份)变量的类型是整数。

其中一些方法在我们需要并且只有一个变量时返回 2 个值。


当我们想要从用户那里获取输入时,我们需要 bufio 包和 NewReader() 函数。

在下面的代码中,我将 bufio.NewReader(os.Stdin) 分配给 reader 变量。

reader := bufio.NewReader(os.Stdin)

此变量的类型是 bufio.Reader。这对我来说很新鲜。

我试图打印出 reader 变量,它向我显示了类似 &{[0.....0] 0x0000e010 00 -1 -1} 的内容。

目前我只知道它是二进制的。


为了能够使用来自命令行的输入,下一步是将读取器变量分配给另一个变量,

但我们还必须调用另一个方法 - ReadString - 在它上面。

input := reader.ReadString('\n') // 出错了

括号中的符文 \n 表示输入数据的结束。

但我们还没有准备好。 ReadString 方法想要返回 2 个值,但我们只分配了一个变量。

一个值是来自命令行的输入,但另一个值通常是有关错误的信息。

现在,我们必须处理错误。


我们将通过添加第二个变量来做到这一点:

fmt.Print("Give me a number: ")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n') // error again
fmt.Println(input)

代码不会再次编译,因为我们总是必须使用所有声明的值。 

我们有两个选择。


a.使用 _(下划线)代替 err。

input, _ := reader.ReadString('\n')

这样,我们将忽略输入数据中有关错误的所有信息。


b.或者我们可以处理错误。 

现在我们需要一个额外的包日志和 Fatal() 函数来打印我们有什么错误并终止我们的程序。

input, err := reader.ReadString('\n')   
log.Fatal(err)  
fmt.Println(input)

但同样,使用 log.Fatal(err) 会停止程序,即使命令行用户输入了一些东西。


我们必须使用 if 语句仅在错误不为零时显示。 

(nil 是一个零值——到目前为止我所知道的关于 nil 的一切)

package main

import (
    "fmt"
    "bufio"
    "os"
    "log"
)

func main() {
    fmt.Print("Give me a number: ")
    reader := bufio.NewReader(os.Stdin)
    input, err := reader.ReadString('\n')
    if err != nil {
        log.Fatal(err)
    }   
    fmt.Println(input)
}

这么多行只打印来自终端的输入数据。


让包裹更加混乱的另一件事;-)

有时我们想要导入一个包,

例如生成随机数的 rand,但在有导入的部分代码中,我们需要给出导入路径 - math/rand。 

之所以如此,是因为来自相似类别的包被分组。

 rand 包与其他库一起用于数学运算。

package main 

import (
    "fmt"
    "math/rand"
)

func main() {
    target := rand.Intn(100) + 1
    fmt.Println(target)
}

上面的代码会生成一个 1 到 100 范围内的随机数。但这只是理论上的。 

如果我们想运行它,我们可以看到相同的数字。 每次我们都会运行它。


如何生成更多随机数? 这是另一个场合的故事。

转:

https://dev.to/makneta/learning-go-day-2-4o64

相关文章