2016-07-05 3 views
1

Я пытаюсь сделать расширение для общего класса, который ограничен типом общего. Это упрощение кода я считаю, должны работать:Ограниченное расширение общего объекта не соответствует типу

struct Thing<T> { 
    var value: T 
} 

struct ContainsStringThing { 
    var stringThing: Thing<String> 
} 

extension Thing where T == String {       // <-- Error location 
    func containedStringThing() -> ContainsStringThing { 
     return ContainsStringThing(stringThing: value) 
    } 
} 

Однако, я получаю следующее сообщение об ошибке:

Требование же типа делает общий параметр «T» необщего

Я искал способ исправить это и нашел предложение использовать протокол для ограничения расширения вместо типа: link to article. После этого, что я в конечном итоге с этим:

protocol StringProtocol { } 

struct Thing<T> { 
    var value: T 
} 

struct ContainsStringThing { 
    var stringThing: Thing<StringProtocol> 
} 

extension Thing where T: StringProtocol { 
    func containedStringThing() -> ContainsStringThing { 
     return ContainsStringThing(stringThing: self)   // <-- Error location 
    } 
} 

Теперь это позволит мне ограничить расширение, но он показывает другое сообщение об ошибке:

Невозможно преобразовать значение типа «Thing < T>» к Ожидаемый тип аргумента «Thing < StringProtocol>»

в принципе теперь знает, что T соответствует протоколу StringProtocol сам по себе, но он не знает об этом, когда речь идет й e всего объекта Thing<T>.

есть ли какое-либо обходное решение для этого или я должен представить его в качестве предложения по эволюции в список быстрой рассылки?

Примечание: весь код тестируется на детской площадке, вы можете просто скопировать и вставить его, чтобы попробовать.

+0

Проблема с вашим вторым кодом заключается в том, что T не соответствует StringProtocol. Это невозможно, потому что у вас есть _no_ типы, соответствующие StringProtocol! (Протокол не является первоклассным и не может соответствовать самому себе.) – matt

+0

Ограниченное расширение должно внутренне декларировать, что T соответствует StringProtocol (в данном случае). Это означает, что вы можете назначить T всем, что ожидает тип, соответствующий StringProtocol. По той же логике тип объекта, который является Thing , также должен быть эквивалентен Thing , для этого достаточно информации. – gabriellanata

ответ

0

В качестве обходного пути вы можете создать новый экземпляр Thing со значением от себя.

extension Thing where T: StringProtocol { 
    func containedStringThing() -> ContainsStringThing { 
     return ContainsStringThing(stringThing: Thing<StringProtocol>(value: self.value)) 
    } 
} 

В Swift 2.2 такое расширение ограничение означает, что containedStringThing() функция будет доступна, например, вещи, тип которого значение соответствует StringProtocol.

Было бы хорошо, если Swift компилятор может вывести тип self.value в StringProtocol. В таком случае вы могли бы просто написать ContainsStringThing(stringThing: self) вместо ContainsStringThing(stringThing: Thing<StringProtocol>(value: self.value)). Вы должны обязательно заполнить предложение.

+0

К сожалению, это не сработает для меня. Как я сказал в сообщении, это упрощение проблемы, объект Thing намного сложнее, и просто передать внутреннее значение будет недостаточно. – gabriellanata

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