财富之旅_专业流程控制之路

财富之旅

A few words before we start. You can find the code used in this tutorial in this repository. You can find the full contents of Road to Go Pro here. If you missed the last one, you can find it via this link.

在我们开始之前的几句话。 您可以在此存储库中找到本教程中使用的代码 您可以在此处找到Road to Go Pro的完整内容 如果错过了最后一个,可以通过此链接找到它

We talked about the basic types and data structures in the last part of the tutorial. In this one, we will talk about flow control, loops and thefmt package.

在本教程的最后一部分中,我们讨论了基本类型和数据结构。 在这一节中,我们将讨论流控制,循环和fmt包。

流量控制 (Flow Control)

如果(if)

Firstly, let’s look at the if statement. One of the most basic flow controls is if and else statements. They control the program to execute different code blocks based on conditions. The syntax of if statement looks like this.

首先,让我们看一下if语句。 最基本的流程控制之一是if和else语句。 它们控制程序根据条件执行不同的代码块。 if语句的语法如下所示。

if…else… condition pseudocode
如果…否则…条件伪代码

When conditionA in the if statement returns true, then the code inside the if brackets will execute. Otherwise, the conditions below will be evaluated in sequence until reaches the last else code block. Go evaluates conditionB next and if conditionB returns true, the code inside will execute. If conditionB returns false, then the last code block will execute. In a combination of if, else if and else statements, the order of evaluations is always from top to the bottom. Therefore, else is used as a catch-all block in the end. Of course, you can omit the last else block if you don’t need a catch-all function.

如果if语句中的conditionA返回true,则将执行if括号内的代码。 否则,将依次评估以下条件,直到到达最后一个else代码块。 Go接下来评估conditionB,如果conditionB返回true,则将执行其中的代码。 如果conditionB返回false,则将执行最后一个代码块。 在ifelse ifelse语句的组合中,求值顺序始终是从上到下。 因此, else最终将用作万能的块。 当然,如果不需要包罗万象的功能,则可以省略最后一个else块。

So what does a condition look like? Any statements that return a boolean value can be placed in the condition. Here is an example. By the way, we have been using fmt.Println for a while but I haven’t introduced it officially. In the last section of this tutorial, we will talk about the fmt package.

那么条件是什么样的呢? 任何返回布尔值的语句都可以放在条件中。 这是一个例子。 顺便说一句,我们已经使用fmt.Println时间了,但是我还没有正式介绍它。 在本教程的最后一部分,我们将讨论fmt包。

if…else… example
如果...否则...示例

You can also use logical operators in conditions. There are three logical operators, namely and (&&), or (||), not(!). Conditions can be chained together via logical operators to form complex conditions.

您还可以在条件中使用逻辑运算符。 存在三个逻辑运算符,分别是和( && )或( || ),不是( ! )。 条件可以通过逻辑运算符链接在一起以形成复杂的条件。

complex condition example
复杂条件示例

There is no limit on how many else if statements you can write in a chain of if…else if … else. Whereas for the benefit of readability, we do not recommend having a long list of if/else statements. switch is the right choice to handle this scenario. Before we get to it, I want to introduce a special syntax of if statements in Go to you.

您可以在if…else if … else链中编写多少else if语句没有其他限制。 出于可读性的考虑,我们不建议一长串if / else语句。 switch是处理这种情况的正确选择。 在开始之前,我想在Go to you中引入if语句的特殊语法。

Go can accept a “short statement” before the condition in if/else if statements. This syntax makes the code more concise. It is widely used for error handling, which we will cover in later tutorials. Let’s take a look at an example of this syntax.

Go可以在if / else if语句中的条件之前接受“简短声明”。 此语法使代码更简洁。 它被广泛用于错误处理,我们将在以后的教程中介绍。 让我们看一下这种语法的一个例子。

short statement in if
简短的陈述

A “short statement” is a declaration of one or more variables: they are short-lived and only accessible inside the closest brackets. In the example above, if we try to access the variable in the short statement outside the if code block, we will get an error back. A common error handling pattern in Go uses short statements to check if there is an error returned by a function. Since the error returned is only related to the if condition, we can use the “short statement” syntax to make code more concise and avoid confusions of variable scopes.

“简短声明”是对一个或多个变量的声明:它们是短期的,只能在最接近的括号内访问。 在上面的示例中,如果尝试在if代码块外部的short语句中访问变量,则会返回错误。 Go中常见的错误处理模式使用短语句来检查函数是否返回错误。 由于返回的错误仅与if条件有关,因此我们可以使用“短语句”语法使代码更简洁并避免变量范围的混淆。

Variable scope

可变范围

Let me quickly explain what the scope of a variable is. Not all variables are declared equally. Their accessibility depends on the place of declarations. For instance, if a variable is declared inside an if block, we can only access it inside the same code block, not from outside. A general rule of thumb is: the reach of a variable is bounded with its closest brackets ({}).

让我快速解释一下变量的范围是什么。 并非所有变量都被平等地声明。 它们的可访问性取决于声明的位置。 例如,如果在if块内声明了变量,则我们只能在同一代码块内访问它,而不能从外部访问它。 一般的经验法则是:变量的范围以其最接近的方括号( {} )为界。

variable scopes example
可变范围示例

In the example above, anotherPlace and newPlace are only accessible within the closest brackets around them. If there’s no bracket around a variable, then it is a global variable inside the package. We will discuss accessibility when we touch on packages. For now, remembering the bracket rule is sufficient.

在上面的示例中,只能在最近的方括号内访问anotherPlacenewPlace 。 如果变量周围没有括号,则它是包内的全局变量。 当我们接触软件包时,我们将讨论可访问性。 现在,记住括号规则就足够了。

开关 (switch)

Alright, enough distractions. Let’s get back to the flow control. I mentioned that when we have a long list of conditions, it’s better to use switch statements than if statements. switch is a cleaner form of if, which looks like this.

好吧,足够的干扰。 让我们回到流控制。 我提到过,当条件列表很长时,使用switch语句比使用if语句更好。 switchif的更干净形式,它看起来像这样。

switch example
开关例子

The example switch statement can be transformed to the below if statement.

可以将示例switch语句转换为以下if语句。

transform switch to if…else…
转换为if ... else ...

The switch statement compares its associated variable with values in the case statements inside. If it finds a match, the code inside that case block will be executed. Once that block is finished, the program exits the switch block without checking other cases. The last default block is like the else statement.

switch语句将其关联变量与内部case语句中的值进行比较。 如果找到匹配项,则将执行该case块中的代码。 该块完成后,程序将退出切换块,而不检查其他情况。 最后一个default块类似于else语句。

You might not feel it is easier to write switch statement if there are only 3 conditions to check. But imagine if you need to write 10 conditions like this. switch will look much cleaner and concise than if.

如果只检查3个条件,您可能会觉得编写switch语句比较容易。 但是,假设您是否需要编写10个这样的条件。 switch会看起来比更加干净,简洁if

switch also has a more generic form where we don’t need to specify a variable after it. Instead, conditions can be specified in case statements. For instance:

switch还具有更通用的形式,我们不需要在其后指定变量。 而是可以在case语句中指定条件。 例如:

generic switch statement
通用switch语句

Yes, case conditions in the generic switch statement can be any conditions that fit an if statement (excluding the special short statement syntax).

是的,通用switch语句中的case条件可以是适合if语句的任何条件(特殊的short语句语法除外)。

So when should we use if and when should we use switch? In my opinion, they’re interchangeable in many cases. Personally, I will choose whichever is cleaner visually and uses fewer lines of code.

那么什么时候应该使用if以及什么时候应该使用switch呢? 在我看来,它们在许多情况下都是可互换的。 就个人而言,我将选择视觉上更干净且使用更少代码行的那个。

循环 (Loop)

Image for post
Tine Ivanič on TineIvanič摄Unsplash Unsplash

When we need to execute logic repeatedly, a loop is the best helper. Nobody wants to copy-paste duplicated code over and over again. In other languages, you’ve probably seen loops such as for loops and while loops. But in Go, there is only for loop.

当我们需要重复执行逻辑时,循环是最好的帮助。 没有人愿意一遍又一遍地复制粘贴重复的代码。 在其他语言中,您可能已经看到了诸如for循环和while循环之类的循环。 但是在Go中,只有for循环。

对于 (for)

For loop has four forms in Go.

For循环在Go中有四种形式。

Basic form

基本形式

The most basic form of for loop looks exactly the same in many languages. For your information, I rarely use this form in real projects.

for循环的最基本形式在许多语言中看起来完全相同。 仅供参考,我很少在实际项目中使用此表格。

for loop — basic form
for循环-基本形式

Let’s quickly go through the basic form syntax.

让我们快速了解一下基本表单语法。

There are three short statements in the for loop above and they are separated by ;s. The first short statement is for initiating the loop index. Usually, it starts with 0. The second short statement is the loop condition. As long as the loop condition is met, the loop keeps executing until the loop condition returns false. And the last statement is the stepping function. We specify what’s going to change in each iteration. Most of the time, it’s going to be increasing/decreasing the loop index. The example above shows us how we can loop through a slice. We start with setting the loop index to 0. The loop should exit after reaching the last element in the slice. Thus, we set the condition to “loop index needs to be smaller than the length of the slice”. Lastly, we set the stepping function to “increase the index by 1”.

上面的for循环中有三个短语句,它们之间用;分隔; s。 第一条简短语句用于启动循环索引。 通常,它以0开头。第二个简短语句是循环条件。 只要满足循环条件,循环就会继续执行,直到循环条件返回false为止。 最后一个语句是步进功能。 我们指定每次迭代中要更改的内容。 大多数时候,它会增加/减少循环索引。 上面的示例向我们展示了如何遍历切片。 我们首先将循环索引设置为0。循环应在到达切片中的最后一个元素后退出。 因此,我们将条件设置为“循环索引需要小于切片的长度”。 最后,我们将步进功能设置为“将索引增加1”。

To be noted, all these three short statements are optional. We will see its different implications below.

需要注意的是,所有这三个简短语句都是可选的。 我们将在下面看到其不同的含义。

While form

虽然形式

There’s no while keyword in Go. While form is just a variant of the basic for loop. If we omit the initiation and stepping function from the basic form, we will get the while form. Therefore, as long as the loop condition is met, the loop will keep executing. The example above can be easily transformed to while form like this.

Go中没有while关键字。 而形式只是基本的for循环的变体。 如果从基本形式中省略启动和步进功能,则将获得while形式。 因此,只要满足循环条件,循环就会继续执行。 上面的示例可以很容易地转换成while形式,就像这样。

for loop — while form
for循环—形式

Endless form

无休止的形式

Endless loop, also known as “dead loop”, is a dangerous loop. Normally, if we have an endless loop, it’s going to break the program because it can devour all the resources the program can get which can crash the host system as a result. That’s normally a very bad thing. However, in Go, there are some special use cases where we can use endless loops for good. For instance, when you want to run an async background process, you can create an endless loop and let it running in background. I promise, that won’t yield a catastrophic outcome. To write an endless loop, just omit all three statements in the basic form.

无限循环,也称为“死循环”,是一个危险的循环。 通常,如果我们有一个无限循环,它将破坏程序,因为它会吞噬程序可以获取的所有资源,从而使主机系统崩溃。 这通常是一件非常糟糕的事情。 但是,在Go中,有一些特殊的用例,我们可以永久使用无限循环。 例如,当您要运行异步后台进程时,可以创建一个无限循环,并使其在后台运行。 我保证,这不会带来灾难性的结果。 要编写一个无限循环,只需忽略基本形式的所有三个语句。

for loop — endless form
for循环-无休止的形式

Of course, I’m not going to break your computer by asking you to run an endless loop directly in the main function. What we are doing here is to run it in a goroutine (will be covered in future). Goroutine enables async processing, hence our endless loop runs in parallel of the main process. While the main process sleeps for 5 seconds, the async process should execute the endless loop continuously until the main process exits. That’s why we see “I’m an endless loop.” printed 5 times in the console.

当然,我不会要求您直接在main函数中运行无限循环来破坏您的计算机。 我们在这里要做的是在goroutine中运行它(将来会介绍)。 Goroutine启用了异步处理,因此我们的无限循环与主进程并行运行。 当主进程Hibernate5秒钟时,异步进程应连续执行无限循环,直到主进程退出。 这就是为什么我们看到“我是一个无尽的循环”的原因。 在控制台中打印5次。

Range operator

范围运算符

Last but not least, let’s talk about the range operator. It helps to easily iterate over types like slices/arrays, maps, channels and strings. Let’s see how we can simplify the basic form.

最后但并非最不重要的一点,让我们谈谈范围运算符。 它有助于轻松地遍历切片/数组,映射,通道和字符串等类型。 让我们看看如何简化基本形式。

for loop — range operator (slice/array)
for循环—范围运算符(切片/数组)

When applying range operator on a slice or an array, it provides two variables for each iteration, namely the index and value of current iteration. Note that these variables are short-lived and scoped to each iteration, and they can only be accessed inside the loop. Usually, we don’t need the index, so we can omit assigning a variable by using _. It will look like this for _, value := range slice {…}. In fact, if you don’t use any of the variables inside the loop, Go will force you to omit them.

在切片或数组上应用范围运算符时,它为每次迭代提供两个变量,即当前迭代的索引和值。 请注意,这些变量是短暂的,范围仅限于每次迭代,并且只能在循环内部访问。 通常,我们不需要索引,因此我们可以省略使用_来分配变量。 for _, value := range slice {…}看起来像这样。 实际上,如果您在循环中不使用任何变量,Go会强制您忽略它们。

Iterating through a map using the range operator also returns two variables. Except, it returns keys instead of indexes for maps.

使用范围运算符遍历地图也将返回两个变量。 除此以外,它返回键而不是地图的索引。

for loop — range operator (map)
for循环-范围运算符(地图)

Similarly, we need to omit any variables returned by the range operator if we don’t use them.

同样,如果不使用范围运算符,则需要忽略它们所返回的任何变量。

Range operator returns two variables when applied on a string, or String type. The first one is the same as slice/array, which is an index. The second one is the Unicode (represented by int32) of the character.

当应用于字符串或String类型时,范围运算符返回两个变量。 第一个与片段/数组相同,后者是一个索引。 第二个是字符的Unicode(用int32表示)。

for loop — range operator (string)
for循环—范围运算符(字符串)

In this example, you can see that we used a new function from the fmt package. It’s time to explain the formatting capabilities of the fmt package. You can skip to the last section to have a sneak peek.

在此示例中,您可以看到我们使用了fmt包中的新函数。 现在是时候解释fmt软件包的格式化功能了。 您可以跳到最后一部分以进行偷看。

continue & break

继续并中断

continue and break are the short-circuit statements for skipping iterations. When using continue, the program will skip the code execution after continue and start the next iteration. While break is more forceful, the program will skip the entire loop when it sees break.

continuebreak是跳过迭代的短路语句。 当使用continue ,程序将在continue之后跳过代码执行并开始下一个迭代。 尽管break更具强制性,但程序在看到break时将跳过整个循环。

continue & break examples
继续并中断示例

goto & label

转到和标签

goto and label enable jumping from a statement to another line of code in the same function. The convention of label names is to use all capital letters.

gotolabel允许从一条语句跳转到同一函数中的另一行代码。 标签名称的惯例是使用所有大写字母。

goto & label examples
转到和标签示例

goto and label don’t have the best reputation out there. Misusing them can be a sign of spaghetti code, which is something everyone wants to avoid. However, they are not natively evil. They do serve a specific purpose. For instance, in the built-in math package, we can find a proper use of goto statements.

gotolabel没有最好的声誉。 滥用它们可能是意大利面条代码的标志,这是每个人都想避免的事情。 但是,它们不是天生的邪恶。 它们确实有特定的目的。 例如,在内置的数学包中,我们可以找到对goto语句的正确使用。

defer

推迟

defer is the last flow control statement I want to cover in this tutorial. It is used for deferring function execution until the closest surrounding function exits. Here is an example.

defer是我要在本教程中介绍的最后一个流控制语句。 它用于推迟执行功能,直到最接近的周围功能退出。 这是一个例子。

defer example
延迟的例子

As shown in the example, the statements after defer were executed in the end when exiting the main function. To be noted, the execution sequence of a series of defer statements is reversed. In other words, the last stated defer will execute first when exiting the function. Also, the arguments inside defer statements are evaluated inline. That is the only thing which is not deferred.

如示例所示, defer之后的语句在退出main函数时最终执行。 要注意的是,一系列defer语句的执行顺序是相反的。 换句话说,最后一个声明的defer将在退出函数时首先执行。 另外, defer语句中的参数是内联求值的。 那是唯一不被推迟的事情。

defer is useful when we create something that is better to be closed or removed by the end of a function. Without defer, we need to write an open statement in the beginning and then close it in the end. This is error-prone as it’s very easy to forget closing it. With defer, we can write a defer Close() statement right after opening. That way, it’s less likely to forget. We will use it when touching on database connections and HTTP servers in the advanced topics.

当我们创建更好地在函数结束时关闭或删除的内容时, defer很有用。 如果没有defer ,我们需要在开始时编写一个open语句,然后在最后结束。 这很容易出错,因为很容易忘记关闭它。 使用defer ,我们可以在打开后立即编写defer Close()语句。 这样,就不太可能忘记。 当涉及高级主题中的数据库连接和HTTP服务器时,我们将使用它。

奖励内容: fmt软件包 (Bonus content: fmt package)

Image for post
Photo by Jason Leung on Unsplash
照片由 Jason LeungUnsplash拍摄

I’m sure you have seen a lot of fmt.Println functions. We used it a lot to print results in the console. fmt is a powerful built-in formatting package of Go. Println is one of the functions in the package. You can find the documentation of the fmt package here. There are quite a few contents there. I’m not going to go through them one by one in this tutorial. What I want to point out is the formatter in this package. Using formatter can save us time and lines of code when manipulating strings.

我确定您已经看过很多fmt.Println函数。 我们在控制台中大量使用它来打印结果。 fmt是Go的强大内置格式化软件包。 Println是软件包中的功能之一。 您可以在此处找到fmt软件包的文档。 那里有很多内容。 在本教程中,我不会一一介绍它们。 我要指出的是此程序包中的格式化程序。 使用格式化程序可以在处理字符串时为我们节省时间和代码行。

You will find some of the functions have a trailing “f” in the function name. This is an indication that those functions accept formatter as parameters. So how do we use the formatter? Let’s check out this example of Printf function.

您会发现某些函数在函数名称中带有尾随的“ f”。 这表明这些函数接受格式程序作为参数。 那么我们如何使用格式化程序呢? 让我们看看这个Printf函数的例子。

formatter — basic usage
格式化程序-基本用法

The first parameter in Printf is the format string and the following parameters are the arguments that will replace the format “verbs”. In the example above, format verb %s is replaced by the whoami value. You can place as many arguments as you want after the format string. However, the only requirement is the number of format verbs needs to match the number of arguments.

Printf的第一个参数是格式字符串,以下参数是将替换格式“动词”的参数。 在上面的示例中,格式动词%s替换为whoami值。 您可以在格式字符串后放置任意数量的参数。 但是,唯一的要求是格式动词的数量需要与参数的数量匹配。

The core of this formatter lies in the format verbs, let’s check out different types of format verbs below, if you want to see the full list of format verbs, you can find them in the documentation of fmt package.

该格式化程序的核心在于格式动词,让我们在下面查看格式动词的不同类型,如果要查看格式动词的完整列表,可以在fmt软件包的文档中找到它们。

布尔值 (booleans)

The only available format verb for boolean is %t, it will format the boolean value to string value (“true” or “false”).

布尔值唯一可用的格式动词是%t ,它将布尔值格式化为字符串值(“ true”或“ false”)。

formatter — booleans
格式化程序—布尔值

数字(numbers)

Numbers have more format verbs. Here are some of the most widely used ones.

数字具有更多的格式动词。 以下是一些使用最广泛的工具。

  • %b: base 2 number

    %b :以2为底的数字

  • %d: base 10 number

    %d :以10为底的数字

  • %U: Unicode format

    %U :Unicode格式

  • %e/%E: scientific notation

    %e / %E :科学计数法

  • %f: decimal point number

    %f :小数点编号

Let’s see them in action.

让我们看看它们的作用。

formatter — numbers
格式化程序—数字

Note: the format string wrapped with back-ticks are the same as normal double quotes. However, back-tick allows writing a single string in multiple lines.

注意:用反引号引起来的格式字符串与普通的双引号相同。 但是,反引号允许在多行中写入单个字符串。

(strings)

Format verbs for strings:

格式化字符串的动词:

  • %s: string

    %s :字符串

  • %q: string wrapped with double quotes, safely escaped

    %q :用双引号引起来的字符串,已安全转义

formatter — strings
格式化程序-字符串

一般(General)

The verbs mentioned above are for specific types. There are also generic format verbs which work on any types.

上面提到的动词是针对特定类型的。 也有适用于任何类型的通用格式动词。

  • %v`: value in default format

    %v v`:默认格式的值

  • %+v: prints field names when value is a struct

    %+v :当值是结构时打印字段名称

  • %#v: prints Go-syntax representation of the value

    %#v :打印值的Go语法表示形式

formatter — general values
格式化程序-常规值

More often, we don’t really need to print out strings in the console. We only need to format strings and use them in the program. Luckily, there’s another function called Sprintf. It’s the same as Printf, the only difference is Sprintf returns formatted string back as a variable.

通常,我们实际上不需要在控制台中打印出字符串。 我们只需要格式化字符串并在程序中使用它们。 幸运的是,还有另一个名为Sprintf的函数。 与Printf相同,唯一的区别是Sprintf将格式化后的字符串作为变量返回。

下一步是什么? (What’s next?)

Image for post
Photo by Olesya Grichina on Unsplash
Olesya GrichinaUnsplash拍摄的照片

In the next tutorial, we will talk about pointers and functions. Stay tuned and I will see you in the next one.

在下一个教程中,我们将讨论指针和函数。 请继续关注,下一个会见。

Please feel free to leave a comment below if you run into any problems or if you need a helping hand. Feedback is always welcome. Thank you for reading!

如果您遇到任何问题或需要帮助,请随时在下面发表评论。 始终欢迎反馈。 感谢您的阅读!

A special thanks to Mark Hume-Cook for reviewing this tutorial.

特别感谢Mark Hume-Cook审阅了本教程。

翻译自: https://levelup.gitconnected.com/road-to-go-pro-flow-control-dfcc7b9a5395

财富之旅

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值