swift枚举
如何在Swift中正确建模数据 (How to correctly model data in Swift)
In this article, we’re going to learn about enumerations
in Swift or as they’re more commonly known, enums.
在本文中,我们将学习Swift中的enumerations
或更广为人知的枚举 。
An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code — swift.org
枚举为一组相关值定义了通用类型,并使您能够在代码中以类型安全的方式使用这些值— swift.org
Enumerations
are used to model a finite dataset and found commonly in different programming languages. In Swift its history can be traced back to C language but enumerations
in Swift are a lot more flexible.
Enumerations
用于对有限数据集进行建模,并通常在不同的编程语言中找到。 在Swift中,其历史可以追溯到C语言,但是Swift中的enumerations
更加灵活。
为什么枚举:问题 (Why Enumerations: the problem)
Swift offers multiple ways to model data to be used in a program. We can use object and collections to do that. But there is certain kinds of data where normal objects
and collections
don’t quite suffice the need.
Swift提供了多种方法来对要在程序中使用的数据进行建模。 我们可以使用对象和集合来做到这一点。 但是在某些类型的数据中,普通objects
和collections
不能满足需要。
Enumerations
are extensively used to represent fixed set of values.
Enumerations
广泛用于表示固定的一组值。
But what is the issue with normal data types? Let’s understand with help of the following example:
但是普通数据类型有什么问题? 让我们借助以下示例进行了解:
Let’s say we want to model a typical year for a calendar app. To achieve this we can simply declare and array
of String
type and name it months
as follows:
假设我们要为日历应用程序模拟典型年份。 为此,我们可以简单地声明String
类型的array
,并将其命名为months
,如下所示:
So far so good, right? Based on the knowledge of collections it is safe to assume that an array is the best choice here since we only need to identify what month of the year it is.
到目前为止一切顺利,对吗? 根据集合的知识,可以安全地假定数组是此处的最佳选择,因为我们只需要确定数组是一年中的哪个月即可。
Now let’s see what happens when we try to use this data.
现在,让我们看看尝试使用此数据时会发生什么。
Say, our calendar app tries to generate a notification if the given month is in spring season.
说,如果给定的月份是Spring,我们的日历应用会尝试生成通知。
![Image for post](https://miro.medium.com/max/9999/1*Uo-Gt6knwVAVrFtt7wKk6g.png)
Let’s consider the following calendar to decide if a month is in spring or not.
让我们考虑以下日历来确定一个月是否在Spring。
If the given month is within a season as described in table then the function will return respective season, for example for January the function should return Winter.
如果给定的月份在表中所述的季节之内,则该函数将返回相应的季节,例如,对于一月,该函数应返回Winter 。
If an invalid month is passed in as an argument to the function then the function should return Invalid month since our table does not recognise anything other than the given twelve months. Our function will be written as follows:
如果将无效月份作为参数传递给该函数,则该函数应返回无效月份,因为我们的表无法识别给定的十二个月以外的任何内容。 我们的函数将编写如下:
Notice how careful the developer has to be while calling the function. If call to the function has a typo in it, the outcome would be totally different from expectation and that makes this logic really unreliable. For example, let’s assume that the developer using above function wanted to know the result for “April” but instead of passing in “April” as a string he/she made a typo and passed in “Arpil” to the function which would result “Invalid month” as the outcome and not what he/she would have expected.
注意开发人员在调用函数时必须非常小心。 如果对函数的调用中有错字,结果将与预期完全不同,这将使此逻辑确实不可靠。 例如,假设使用上述函数的开发人员想知道“ April ”的结果,但是他/她没有输入“ April ”作为字符串,而是输入了错字,然后将“ Arpil ”传递给该函数,结果是“ 无效的月份 ”作为结果,而不是他/她所期望的结果。
Also, imagine if the logic of the function itself had a flaw in it because of a typo and instead of checking “September” in the fourth case, we were checking for “Setpember” as follows:
此外,想象一下,如果函数的逻辑本身它,因为有一个错字,而不是在第四种情况检查“ 九 ”,我们检查“Setpember”如下的和缺陷:
In this scenario even if the call to the function is made with correct arguments, the function will never return expected result as shown in the following screenshot:
在这种情况下,即使使用正确的参数调用函数,该函数也永远不会返回预期结果,如以下屏幕截图所示:
![Image for post](https://miro.medium.com/max/9999/1*GKxpcsh6scDKotJ99HkAVg.png)
列举救援 (Enumerations to the rescue)
In the previous section we noticed that the path we took was fraught with peril.
在上一节中,我们注意到我们所走的道路充满了危险。
One thing that we learnt was that using strings as values, in cases like these, as a value to determine the next step in our process is a terrible decision and results in mistakes that are often quite hard to catch.
我们了解到的一件事是,在这样的情况下,使用字符串作为值来确定流程下一步的值是一个糟糕的决定,并导致错误常常很难发现。
So how can we solve this? and make use of Swift’s type safety to help us at compile time to make sure that we aren’t doing anything terribly wrong.
那么我们该如何解决呢? 并利用Swift的类型安全性在编译时帮助我们,以确保我们没有做任何非常错误的事情。
解决问题 (Solution to the problem)
Let’s try and solve the same problem but get rid of those strings altogether and use an enum
. This time, instead of an array of months, we will create an enum named Month
as follows:
让我们尝试解决相同的问题,但是完全摆脱这些字符串,并使用enum
。 这次,而不是几个月的数组,我们将创建一个名为Month
的枚举,如下所示:
Inside the body of this enum, we have defined member values. Each month of the year is a different member. We can now use this datatype in the our previous function as follows:
在该枚举的主体内部,我们定义了成员值。 一年中的每个月都是不同的成员。 现在,我们可以在以前的函数中使用此数据类型,如下所示:
func season(for month: Month) -> String {}
and since the values inside enumeration
are finite, when we switch
over month
inside the function you will notice that we don’t require the default case:
并且由于enumeration
内的值是有限的,因此当我们在函数内switch
month
,您会注意到我们不需要默认情况:
also, while using the member values you’ll notice something interesting. The moment you put that dot next to Month
and start typing, Xcode
starts auto completing for us as shown in the image below:
同样,在使用成员值时,您会注意到一些有趣的事情。 当您将点放在Month
旁边并开始输入时, Xcode
将为我们自动完成,如下图所示:
![Image for post](https://miro.medium.com/max/9999/1*W148VhtEDJLBH2vjZ1qLGA.png)
There’s that compiler help we were hoping for earlier.
我们早就希望有编译器的帮助。
Because this is an actual type we defined with a set range of values, the compiler knows the different options and presents them. It makes it impossible to make a mistake.
因为这是我们定义的实际类型,具有一定范围的值,所以编译器知道不同的选项并提供它们。 这使得不可能犯错。
We simply use the type, a dot, and then it’s like we’re accessing a property. Now, let’s say I typed Setpember, like that mistake we made earlier. Well, because this is an actual value and not a string, we typed value, you’ll notice that the compiler complains that the enum case isn’t found as shown below:
我们只使用类型,点,然后就像访问属性一样。 现在,假设我输入了Setpember ,就像我们之前犯的那个错误。 好吧,因为这是一个实际值而不是字符串,所以我们键入了值,您会注意到编译器抱怨找不到枚举大小写,如下所示:
![Image for post](https://miro.medium.com/max/9999/1*8bA5iLoIOzFKja8NBXestw.png)
Hence with the compiler help, we’ve eliminated the possibility of typing an incorrect value.
因此,借助编译器帮助,我们消除了键入错误值的可能性。
为什么在这种情况下我们不需要默认情况? (Why don’t we need a default case in this scenario?)
The switch
statement is exhaustive by nature which means that it needs to covers all possible paths for the value of the type on which we are switching the control.
switch
语句本质上是详尽无遗的,这意味着它需要覆盖我们要在其上切换控件的类型的值的所有可能路径。
In the earlier scenario when we were switching on the String
type a default
case was required as we only covered names of the months in custom cases leaving behind a plethora of other possibilities. So, a default case was required to handle all those possibilities but in the second scenario since we were only switching on a finite set of data we did not require a default statement as all the possible cases were covered by custom cases.
在较早的场景中,当我们打开String
类型时,需要一个default
情况,因为我们仅在自定义情况中涵盖月份的名称,而留下了许多其他可能性。 因此,需要一个默认案例来处理所有这些可能性,但是在第二种情况下,由于我们只切换了一组有限的数据,因此我们不需要默认语句,因为所有可能的案例都已被自定义案例覆盖。
The compiler keeps a close eye on what we’re doing. For example, if we remove this Month.April case, the compiler immediately knows that all paths aren’t considered, and complains that the switch statement must be exhaustive as shown below:
编译器密切关注我们在做什么。 例如,如果删除此Month.April情况,则编译器立即知道未考虑所有路径,并抱怨switch语句必须是穷举性的,如下所示:
![Image for post](https://miro.medium.com/max/9999/1*JLuCYVtz8PbpBWeaV9RVPQ.png)
We can either add a case for April or a default case to fix this.
我们可以添加4月的案例,也可以添加默认案例来解决此问题。
将计算的属性添加到枚举 (Adding a computed property to the Enumeration)
Another way in which we can eliminate the requirement for a separate function
season is by adding a computed property to the enumeration
. So we will replace the following function:
我们可以消除对单独的function
季节的要求的另一种方法是通过向enumeration
添加计算属性 。 因此,我们将替换以下功能:
func season(for month: Month) -> String {}
with the computed property season
as shown in the code block below:
带有计算的属性season
,如下面的代码块所示:
Now, we can simply use the computed property on the enumeration as follows:
现在,我们可以简单地对枚举使用计算属性,如下所示:
![Image for post](https://miro.medium.com/max/9999/1*wtZdrIkmTDWL4W4D7a5MKQ.png)
结论 (Conclusion)
In this article, we discussed about Enumerations
in Swift. We briefly discussed how enumerations
can help in solving certain programming issues and write bug free code.
在本文中,我们讨论了Swift中的 Enumerations
。 我们简要讨论了enumerations
如何帮助解决某些编程问题并编写无错误代码。
In the beginning of the chapter we mentioned that Swift enums are very powerful when compared to many other languages. We will cover some of those features in upcoming articles, like the raw representable form, associated values and protocol conformance.
在本章的开头,我们提到,与许多其他语言相比, Swift枚举非常强大。 我们将在后续文章中介绍其中的一些功能,例如原始可表示形式,关联值和协议一致性。
Thanks for reading, please share it if you found it useful 🙂
感谢您的阅读,如果发现有用,请分享share
For other updates you can follow me on Twitter on my twitter handle @NavRudraSambyal.
对于其他更新,您可以在我的Twitter句柄@NavRudraSambyal的 Twitter上关注我。
翻译自: https://medium.com/swlh/swift-enumerations-71ec97584345
swift枚举