2017-02-21 76 views
1

我试图让与RawRepresentable可选参数的通用failable初始化,RawRepresentable初始化基本上这https://www.natashatherobot.com/swift-failable-enums-with-optionals/斯威夫特。可选RawValue

有一对夫妇的方法建议,其中之一就是这个(编辑:第二个条款中的固定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

我不知道,如果它曾经工作斯威夫特2,但我不能编译它斯威夫特3.我得到:

Command failed due to signal: Segmentation fault: 11 

有没有办法让它工作?

P.S.我知道文章及其评论的其他方法。

编辑:修复破碎的复制/粘贴的代码。

+0

编译器不应该崩溃,所以这显然是一个错误。但它似乎在Swift 3.1中得到了修复(可用于Xcode 8.3 beta)。 – Hamish

+0

[文件错误](http://bugs.swift.org)关于崩溃,当然 - 没有代码,但是可能会损坏,应该会导致编译器崩溃。 – rickster

回答

0

我刚刚在Playground中复制并粘贴了您的代码,我得到的唯一错误是它在guard语句中分配value之前缺少let

你确定分段错误是因为这个扩展吗?

这是对我的作品的代码(Xcode的8.2.1,3.0.2斯威夫特):

extension RawRepresentable { 

    init?(rawValue optionalRawValue: RawValue?) { 

     guard let rawValue = optionalRawValue, let value = Self(rawValue: rawValue) else { return nil } 

     self = value 
    } 
} 

- 编辑 -

与原始值定义enum后,我确实出现错误。

添加这使得游乐场崩溃:

enum Counter: Int { 
    case one = 1, two, three, four, five 
} 

固定它通过重命名参数init?init?(optRawValue optionalRawValue: RawValue?)。我想问题是你在init?里面调用Self(rawValue: rawValue),编译器不知道使用哪一个...

+0

我试图定义'init?(rawExtValue rawValue:RawValue)'并使用它来执行'let value = Self(rawExtValue:rawValue)'但我仍然得到相同的错误。正如我在我的问题中所述,我意识到其他方法,但我想使用'init?(rawValue optionalRawValue:RawValue?)'来工作。或者至少理解编译器崩溃的原因。 – user1264176

+0

看到这个问题得到更多关于为什么编译器崩溃的细节:http://stackoverflow.com/questions/19014359/how-do-i-view-the-full-build-log-on-xcode5 –

+1

另外,你应该在https://bugs.swift.org提交一个错误 –

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 
        } 
    } 
    

无论哪种方式,你展开期权的两个级别(segue是否有标识符,以及该字符串是否为您的SegueIdentifier枚举的有效原始值)switch之前,这意味着switch必须处理所有有效的SegueIdentifier个案。反过来,这意味着如果您稍后添加一个新的SegueIdentifier箱子,并且不处理它,那么您会抓住自己。 (相对于switch荷兰国际集团的东西,可能是一个有效的SegueIdentifier或可能是零,这意味着你需要一个default情况下,这意味着如果有新的SegueIdentifier是你应该被处理,你会默默的失败。)

+0

好吧,我解析了很多JSON,这意味着检查每个可能的零值的开销是巨大的,它只会带来代码重复。我认为我们必须实践,甚至可以说,每个带有一个参数的可分解初始化器应该总是接受可选参数。如果他愿意,程序员有责任检查输入。但我同意,如果它只有在论证是零的情况下才会失败,那么它根本不应该失败。 – user1264176