Ограничения расширений протокола и значения по умолчанию в swift2

Итак, я играл с расширениями протокола и столкнулся с «интересной» проблемой.

Я хотел написать тип единиц Meters и Kilometers для проверки некоторых вещей. ОЧЕНЬ легко сделать это как класс, в котором есть базовый класс, и оба подкласса переопределяют базу, просто переопределяя простое значение.

//Conversion factor between types
enum DISTANCE_UNIT_TYPE : Double {

    case METER = 1.0;
    case KILOMETER = 0.001;
}

protocol DistanceUnit {

    var unitType : DISTANCE_UNIT_TYPE {get}
    var value : Double { get set }
    var baseValue : Double { get set }
}


struct Kilometers : DistanceUnit {

    var unitType = DISTANCE_UNIT_TYPE.KILOMETER
    var value : Double
    var baseValue : Double

    init(_ v : Double) {
        value = v
        baseValue = v * unitType.rawValue
    }
}


struct Meters : DistanceUnit {

    var unitType = DISTANCE_UNIT_TYPE.METER
    var value : Double
    var baseValue : Double

    init(_ v : Double) {
        value = v
        baseValue = v * unitType.rawValue
    }
}

Итак, как вы можете видеть, у меня много повторяющегося кода (в частности, инициализаторы)

Я попытался сделать расширение протокола, чтобы установить инициализатор по умолчанию.

extension DistanceUnit {

    init(_ v : Double) {
        value = v
        baseValue = v * unitType.rawValue
    }
}

но я получаю сообщение об ошибке переменная 'self' передается по ссылке перед инициализацией

Есть ли способ заставить это работать или мне просто нужно ввести много повторяющегося кода? Может быть, используя unsafe или что-то в этом роде?


person Jeef    schedule 03.07.2015    source источник
comment
это может быть достигнуто ... но я думаю, что мы сможем найти обоснование того, как это работает в следующем - > [p] протоколы могут быть расширены, чтобы предоставить реализации методов и свойств для соответствующих типов - однако инициализаторы не являются методами , руководство по языку программирования говорит нам, что инициализаторы... подобны специальным методам -> так что, возможно, мы можем сделать вывод, что мы не должны предоставлять реализации по умолчанию для инициализаторов с использованием расширения протокола?   -  person fqdn    schedule 03.07.2015


Ответы (1)


Я предполагаю, что fqdn прав, и мы не сможем использовать пользовательские инициализации внутри расширения протоколов, как нам хотелось бы, но только время покажет.

Но есть еще обходной путь:

struct Meters : DistanceUnit {

    var unitType = DISTANCE_UNIT_TYPE.METER
    var value : Double
    var baseValue : Double

    init() { // this one is needed as designated initializer for your protocol extension
        value = 0
        baseValue = 0
    }
}

protocol DistanceUnit {

    var unitType : DISTANCE_UNIT_TYPE {get}
    var value : Double { get set }
    var baseValue : Double { get set }
    init() // this is new and you will NEED to implement this in your structure or class
}

extension DistanceUnit {

    init(_ v : Double) {
       self.init()
       value = v
       baseValue = v * unitType.rawValue
    }

    // you can now implement a lot more different default inits and they should work fine here :)
    // here is a quick example

    init(_ s : String) {
       self.init(Double(s.characters.count))
    }
}

Надеюсь, это поможет вам. Я научился этому трюку несколько дней назад, когда создавал собственный универсальный генератор синглетонов с расширениями протокола (см. здесь).

person DevAndArtist    schedule 08.07.2015