2017-02-21 7 views
1

Я пытаюсь сделать общий failable инициализатору с дополнительным параметром для RawRepresentable, в основном это https://www.natashatherobot.com/swift-failable-enums-with-optionals/Swift. RawRepresentable INIT с дополнительным RawValue

Существовали несколько предложенных методов один из которых заключается в следующем (EDIT: фиксированный 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

Компилятор никогда не должен терпеть крах, так что это явно ошибка. Однако он, как представляется, исправлен в Swift 3.1 (доступен с бета-версией Xcode 8.3). – Hamish

+0

[File bug] (http://bugs.swift.org) о сбое, конечно же - никакой код, каким бы сломанным он ни был, должен скомпрометировать компилятор. – rickster

ответ

0

Я только что скопировал и наклеил ваш код на игровой площадке, и единственная ошибка, которую я получаю, заключается в том, что ему не хватает let перед назначением value в инструкции guard.

Вы уверены, что ошибка сегментации является причиной этого расширения?

Это код, который работает для меня (Xcode 8.2.1, 3.0.2 Swift):

extension RawRepresentable { 

    init?(rawValue optionalRawValue: RawValue?) { 

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

     self = value 
    } 
} 

- EDIT -

После определения enum с сырыми значениями I сделайте ошибку.

Добавление это делает площадку врезаться:

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

Fixed его переименования параметра в init? быть init?(optRawValue optionalRawValue: RawValue?). Я предполагаю, что проблема заключается в том, что вы вызываете Self(rawValue: rawValue) внутри init?, а компилятор не знает, какой из них использовать ...

+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 поощряет обработку и разрешение вопросов с невозбуждением при первой же возможности, а не каскадные сбои до сих пор, что трудно восстановить их происхождение. Если у вас есть функция/инициализатор, который возвращает 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 (дважды), который выполняет замыкание тогда и только тогда его вход не ноль:

    segue.identifier.flatMap(SegueIdentifier.init).flatMap { identifier in 
        switch identifier { 
         // handle all cases 
        } 
    } 
    

В любом случае, вы разворачивания оба уровня диспозитивности (есть ли у segue идентификатор и является ли эта строка действительным необработанным значением для вашего перечисления SegueIdentifier) доswitch, что означает, что switch должен обрабатывать все действующие SegueIdentifier чехлы. В свою очередь, это означает, что вы поймаете себя, если позже вы добавите новый корпус SegueIdentifier и не будете его обрабатывать. (В отличие от switch ИНГ на то, что может быть допустимым SegueIdentifier или может быть нулевым, что означает, что вам нужно default случай, который означает, что вы будете молча терпеть неудачу, если есть новый SegueIdentifier s вы должны быть обработка.)

+0

Ну, я разбираю много JSON, что означает, что накладные расходы для проверки каждого возможного значения nil являются большими, и это просто приведет к дублированию кода. Я утверждаю, что мы должны быть практичными и даже догадаться, что каждый неудачный инициализатор с одним параметром должен всегда принимать необязательный аргумент. Ответственность программиста заключается в проверке ввода, если он этого пожелает. Я согласен с тем, что если он терпит неудачу, только если аргумент равен нулю, он не должен быть вообще провальным. – user1264176

Смежные вопросы