迅速。具有可选RawValue

时间:2017-02-21 16:59:27

标签: swift initialization protocols

我正在尝试使用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。我知道文章中的其他方法及其评论。

编辑:修复了损坏的复制/粘贴代码。

3 个答案:

答案 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帖子中的问题。

  1. 使用复合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
        }
    }
    
  2. 使用flatMap(两次)执行功能样式,如果输入不是nil,则执行闭包:

    segue.identifier.flatMap(SegueIdentifier.init).flatMap { identifier in
        switch identifier {
            // handle all cases
        }
    }
    
  3. 无论哪种方式,您都需要解开两个级别的可选性(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>