我正在尝试使用RawRepresentable的可选参数创建一个通用的可用初始值设定项,基本上是https://www.natashatherobot.com/swift-failable-enums-with-optionals/
提出了几种方法,其中一种方法就是这样(编辑:第二项中的固定let
):
extension RawRepresentable {
init?(rawValue optionalRawValue: RawValue?) {
guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil }
self = value
}
}
从这里https://gist.github.com/okla/e5dd8fbb4e604dabcdc3
我不知道它是否曾在Swift 2上运行但我无法在Swift 3上编译它。我得到:
Command failed due to signal: Segmentation fault: 11
有没有办法让它发挥作用?
P.S。我知道文章中的其他方法及其评论。
编辑:修复了损坏的复制/粘贴代码。
答案 0 :(得分:1)
我刚刚在Playground中复制并粘贴了您的代码,我唯一的错误就是在let
语句中分配value
之前它错过了guard
。
你确定分段错误是因为这个扩展吗?
这是适用于我的代码(Xcode 8.2.1,Swift 3.0.2):
extension RawRepresentable {
init?(rawValue optionalRawValue: RawValue?) {
guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil }
self = value
}
}
- 编辑 -
使用原始值定义enum
后,我确实收到错误。
添加此项会使Playground崩溃:
enum Counter: Int {
case one = 1, two, three, four, five
}
通过将init?
中的参数重命名为init?(optRawValue optionalRawValue: RawValue?)
来解决此问题。我想问题是你在Self(rawValue: rawValue)
内调用init?
,编译器不知道要使用哪一个......
答案 1 :(得分:1)
无论编译此代码或使其按照您喜欢的方式运行存在问题,我都认为您正试图以错误的方式解决潜在问题。
尝试设计这样的初始化程序是一种反模式:Swift中Optionals的设计鼓励尽早处理和解决可空性问题,而不是到目前为止的级联失败,以至于很难恢复它们的起源。如果你有一个函数/初始化程序,当且仅当它通过nil时才返回nil,它首先不应该接受nil并且永远不会返回nil。
在Swift 3中,您可以为枚举保留默认的rawValue初始化程序,并通过几种不同的方式解决原始NatashaTheRobot帖子中的问题。
使用复合if
(或guard
)语句。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let string = segue.identifier,
let identifier = SegueIdentifier(rawValue: string)
else { return /* or fatalError or whatever for catching problems */ }
switch identifier {
// handle all the enum cases here
}
}
使用flatMap
(两次)执行功能样式,如果输入不是nil,则执行闭包:
segue.identifier.flatMap(SegueIdentifier.init).flatMap { identifier in
switch identifier {
// handle all cases
}
}
无论哪种方式,您都需要解开两个级别的可选性(segue是否具有标识符,以及该字符串是否为SegueIdentifier
枚举的有效原始值)之前 switch
,这意味着switch
必须处理所有有效SegueIdentifier
个案件。反过来,这意味着如果您以后添加新的SegueIdentifier
案例并且不处理它,您就会抓住自己。 (与switch
可能是有效的SegueIdentifier
或可能是nil的内容相反,这意味着您需要一个default
案例,这意味着如果出现这种情况,您将无声地失败是你应该处理的新SegueIdentifier
。)
答案 2 :(得分:0)
必须向init添加public并编译并传递测试
Apple Swift版本4.1.2(swiftlang-902.0.54 clang-902.0.39.2) 目标:x86_64-apple-darwin17.6.0
mockit cannot be found.
<jmockit-version>1.38</jmockit-version>
<junit-jupiter-version>5.2.0</junit-jupiter-version>
<maven-surefire-plugin>2.21.0</maven-surefire-plugin>
<junit-platform-runner-version>1.2.0</junit-platform-runner-version>
<junit-platform-surefire-version>1.2.0</junit-platform-surefire-version>
<mockito-junit-jupiter-version>2.18.3</mockito-junit-jupiter-version>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin}</version>
<configuration>
<argLine> javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit-version}/jmockit-${jmockit-version}.jar
-XX:-UseSplitVerifier -Xmx512m -XX:MaxPermSize=256m ${argLine}
</argLine>
</configuration>
</plugin>
<!-- Testing -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit-jupiter-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junit-platform-runner-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito-junit-jupiter-version}</version>
<scope>test</scope>
</dependency>