2016-04-04 5 views
1

Я пытаюсь создать метод, который принимает массив структур, которые соответствуют протоколу в Swift.Массив структур, соответствующих протоколу, не распознан

Для простейшего примера этого, я определяю пустой протокол и метод, который принимает массив объектов, соответствующих этот протокол и просто печатаю их

protocol SomeProtocol {} 

func methodTakingProtocol(objects: [SomeProtocol]) { 
    // do something with the array of objects 
    print(objects) 
} 

Когда я пытаюсь накормить этот метод массив Структуры, которые соответствуют SomeProtocol, однако, я получаю сообщение об ошибке

struct SomeStruct: SomeProtocol {} 

let arrayOfStructs = [ SomeStruct(), SomeStruct() ] 

methodTakingProtocol(arrayOfStructs) 
//^"Cannot convert value of type '[SomeStruct]' to expected argument type '[SomeProtocol]'" 

ковыряться немного, я обнаружил, что я могу обойти эту проблему, явно взывает принятие SomeStruct «х SomeProtocol

let arrayOfStructs: [SomeProtocol] = [ SomeStruct(), SomeStruct() ] 

// This will work 
methodTakingProtocol(arrayOfStructs) 

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

+1

Я не думаю, что это ошибка. Компилятор видит экземпляры 'SomeStruct' и поэтому задает тип массива' [SomeStruct] '. Чтобы изменить тип, вам нужно сделать свое намерение явным. Однако вы можете зарегистрировать радар функции. – dasdom

+0

Связанные: http://stackoverflow.com/questions/34820240/assigning-an-array-of-structs-to-an-array-of-protocols. –

ответ

0

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

protocol SomeProtocol {} 

struct SomeStruct: SomeProtocol {} 

// explicitly typed 
let arrayOfStructs:[SomeProtocol] = [ SomeStruct(), SomeStruct() ] 

func foo(bar:[SomeProtocol]) { } 

foo(arrayOfStructs) // Works! 

Вот отличная статья на эту тему: Generic Protocols & Their Shortcomings

Но напрашивается вопрос; Почему мы не можем использовать общие протоколы вне общих ограничений?

Короткий ответ: Swift хочет быть безопасным по типу. Поделитесь этим с фактом, что это язык компиляции с опережающим временем, и у вас есть язык , который НЕОБХОДИМО иметь возможность вывести конкретный тип в любое время во время компиляции. Я не могу это подчеркнуть. Во время компиляции каждый один из ваших типов, которые не являются ограничениями функции/класса, должен быть бетон. Связанные типы в протоколе являются абстрактными. Что означает , они не являются бетонными. Они поддельные. И никто не любит подделку.

Редактировать: Это по-прежнему отличная статья, но после повторного чтения я понял, что это не совсем верно, поскольку мы обсуждаем «конкретные протоколы», а не «общие протоколы».

+0

Спасибо за эту ссылку! Определенно, много интересной информации на этом посту, хотя, как вы сказали, я не уверен, что это именно то, что относится к этой проблеме. Я собираюсь сделать некоторые копания в документации Apple, когда у меня появится шанс увидеть, есть ли что-нибудь там, что может пролить свет на ситуацию. – Ziewvater

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