美文网首页
枚举(三)

枚举(三)

作者: 小橘子成长记 | 来源:发表于2018-06-04 22:09 被阅读1次

关联值

关联值在表达能力上将枚举提升到更高层次。你可以给每个枚举案例关联自定义的相关值。

以下是关联值的特性:
1 每个枚举案例都有零个或多个关联值。
2 每个枚举的关联值都有自己的数据类型。
3 可以像定义命名函数参数那样,用定义关联值。

枚举可以具有原始值或关联值,但不能同时具有这两个值。

在上一个小练习中,你定义了一个硬币钱包。假设你把钱存到银行。然后你可以去自动取款机取钱:

var balance = 100
func withdraw(amount: Int) {
  balance -= amount
}

自动取款机永远不会让你取比你存的多的钱,所以它需要一种让你知道交易是否成功的方法。可以将其作为枚举的相关值来实现:

enum WithdrawalResult {
  case success(newBalance: Int)
  case error(message: String)
}

每种情况都有一个值。对于成功情况,关联的Int将保持新的平衡;对于错误情况,关联的字符串将具有某种类型的错误消息。

可以使枚举重写withdraw方法

func withdraw(amount: Int) -> WithdrawalResult {
 if amount <= balance {
   balance -= amount
   return .success(newBalance: balance)
 } else {
   return .error(message: "Not enough money!")
 }
}

现在你可以调用这个方法,处理返回的结果

let result = withdraw(amount: 99)
switch result {
case .success(let newBalance):
  print("Your new balance is: \(newBalance)")
case .error(let message):
  print(message)
}

注意如何使用let 绑定来读取相关联的值。关联值不是你可以自由访问的属性,所以你需要像这样的let绑定来读取它们。记住,绑定的常量newBalance和message在switch case下是局部的。它们不需要具有与关联值相同的名称,虽然这样做是常见的做法。

你可以在调试控制台中看到“你的新余额是:1”。

许多地方通过访问枚举中的关联值来发挥作用。例如,internet服务器经常使用枚举来区分请求的类型:

enum HTTPMethod {
  case get
  case post(body: String)
}

在银行帐户示例中,你希望在枚举中检查多个值。但只有一个符合要求,你可以在if case语句或guard case语句中使用模式匹配。他们是如何工作的:

let request = HTTPMethod.post(body: "Hi there")
guard case .post(let body) = request else {
  fatalError("No message was posted")
}
print(body)

在这段代码中,guard case检查request是否包含post枚举,如果包含,则读取并绑定关联值。

枚举作为状态模式

枚举是一个状态模式的例子,说明它一次只能是一个枚举值,不能是更多。交通灯很好地说明了这个概念:

enum TrafficLight {
 case red, yellow, green
}
let trafficLight = TrafficLight.red

一个交通灯永远不会同时是红色和绿色。你可以在其他现代设备中观察这种状态机行为,这些设备遵循预定的操作序列来响应事件序列。状态机的例子包括:

•自动售货机,当顾客放入足够的钱时,自动售货机就会售货
•下来之前,电梯会把乘客送到楼上。
•组合锁,要求组合号按正确顺序排列

要按预期操作,这些设备依赖于枚举的担保,即每次只能在一个状态。

case-less 枚举

在“方法”中,你学习了如何为一组相关类型方法创建名称空间。那一章的例子是这样的:

struct Math {
  static func factorial(of number: Int) -> Int {
    return (1...number).reduce(1, *)
  }
}
let factorial = Math.factorial(of: 6) // 720

有一件事你当时可能没有意识到,你可以创建一个数学实例,比如:

  let math = Math()

数学实例没有任何用途,因为它完全是空的;它没有任何存储属性。在这种情况下,更好的设计实际上是将Math从一个结构转换为一个枚举:

enum Math {
  static func factorial(of number: Int) -> Int {
    return (1...number).reduce(1, *)
  }
}

let factorial = Math.factorial(of: 6) // 720

如果你尝试做创建一个实例,编译器会给你一个错误:

let math = Math() // ERROR: No accessible initializers

没有case的枚举有时被称为无实例类型或底层类型。

正如在本章开头学到的,枚举是非常强大的。它们可以完成结构所能完成的大部分工作,包括自定义初始化器、计算属性和方法。为了创建枚举的实例,您必须将成员值指定为状态。如果没有成员值,则无法创建实例。

那么Math就无法被实例化,也没什么可实例化的,只有一个方法。这样就可以预防以后的程序员不小心实例化这个类。所以如果你想要创建一个没有值的实例,就可以选择case-less 枚举。

可选值

既然你已经学习了枚举,现在是时候让你知道一个小秘密了。有一个swift语言功能一直在你眼皮底下使用枚举:optional!在本节中,你将探索它们的底层机制。

选项就像容器一样,里面要么有东西,要么什么都没有:

var age: Int?
age = 17
age = nil

optional实际上是列举了两种情况:

  1. .none 没有就意味着没有价值。
  2. .some 表示存在一个值,该值作为关联值附加到枚举案例中。

您可以使用switch语句从optional中提取相关值:

switch age {
case .none:
  print("No value")
case .some(let value):
  print("Got a value: \(value)")
}

你可以在调试控制台中看到输出的“No value”消息。

尽管optionals确实是在后台的枚举,但是Swift隐藏了实现的细节,比如可选绑定,?和!操作符和诸如nil的关键字。

let optionalNil: Int? = .none
optionalNil == nil    // true
optionalNil == .none  // true

如果你在playground运行,你会看到nil和.none是相等的。

在“泛型”章节中,你将了解更多关于可选值optional的底层机制,包括如何编写可选值代码。

要点

•枚举是互斥情况的公共类型列表。
•枚举提供了一种类型安全的替代方法,可以替代老式的整数值。
•你可以使用枚举来处理响应、存储状态和封装值。
•可以使用case-less枚举作为名称空间并防止实例的创建。

相关文章

  • 枚举的概念及应用

    一、枚举的概念 二、枚举类型的定义 三、枚举变量的定义 四、枚举使用的注意 五、枚举变量的基本操作 五、枚举变量的...

  • 位移枚举

    位移枚举 一. OC中常见的三种枚举 C语言枚举 // C语言枚举 typedef enum : NSUInteg...

  • 位移枚举简单介绍

    枚举的三种实现方式 第一种枚举 第二种枚举定义类型 ** 第三种枚举** 位移枚举在这感谢下原文作者[天狐博客]|...

  • 枚举(三)

    关联值 关联值在表达能力上将枚举提升到更高层次。你可以给每个枚举案例关联自定义的相关值。 以下是关联值的特性:1 ...

  • Java enum常见的用法

    一,常量定义 二,swich 三,向枚举添加新方法 四,覆盖枚举方法 五,实现接口 六,接口组织枚举 七,枚举集合...

  • Swift三 一: 枚举 二: 可选项(! ?) 三: gua

    一: 枚举二: 可选项(! ?)三: guard语句 一: 枚举 枚举总结:Swift 中使用 enum 关键词...

  • Java枚举(三)

    枚举的特性 枚举的特性,归结起来就是一句话: 除了不能继承,基本上可以将 enum 看做一个常规的类。 但是这句话...

  • TypeScript学习-枚举

    本篇文章将讲枚举类型的基础知识,枚举与哈希,集合这三者的区别以及各自合适用的场景。 枚举 枚举常用于定义一些带名字...

  • Swift枚举和结构

    枚举 枚举中,成员值是一般是字符类型(不带引号),原始值则可以为Int、Double、String等等 枚举的三个...

  • 枚举的几种写法

    在这里,列举三种枚举的写法。 //枚举定义方法1typedefenum{WYNDemoTypeTop,WYNDem...

网友评论

      本文标题:枚举(三)

      本文链接:https://www.haomeiwen.com/subject/urahsftx.html