2014-09-25 3 views
1

Я недавно загрузил xCode 6 и играл с языком Swift. До сих пор мне это нравится. Я читал на Swift-функциях, и один из них, который мне очень нравится, - это вывод. Однако в образце кода, который я создал для создания протоколов в Swift, я получаю проблему, которую я не совсем понимаю, поэтому надеялся, что кто-то поможет выяснить, что происходит. Возможно, я что-то упускаю. Таким образом, в примере кодаБыстрое поведение, вывод и поведение протокола

Я создал протокол Animal

protocol Animal 
{ 
    func speak() 
} 

Затем я создал класс для собак и кошек, которая соответствует протоколу животного, например,

class Dog: Animal { 

    func speak() 
    { 
     println("Woof"); 
    } 
} 

Затем я создал собак и кошек переменные, чтобы проверить это работает, как не ожидал

var animal1 = Dog() 
    var animal2 = Cat() 

    println(animal1.speak()) 
    println(animal2.speak()) 

Нет проблем до сих пор. Итак, я решил добавить их в массив и петля через объекты и распечатать их

var ar = [animal1, animal2]; 

     for var i = 0; i < ar.count; i++ 
     { 
      var an = ar[i] 

      println(an.speak()) 
     } 

Однако я получаю сообщение об ошибке сказав «AnyObject не соответствует протоколу„Animal“, а также предупреждение о том,» Переменная выводится так, чтобы иметь тип «AnyObject», который может быть неожиданным. Я думал, что из-за вывода, он должен автоматически реализовать Dog и Cat в соответствии с протоколом Animal. Когда я ранее печатал метод разговора, мне не нужно было указывать тип Animal. Так Тогда я обновил переменную внутри метода петли так явно указано, что объект соответствует типу животных, как так

var an : Animal = ar[i] 

Это снимает предупреждение, однако ошибка не будет устранена. Почему это так? Я прямо сказал, что этот объект соответствует протоколу Animal. Я могу сделать это в Objective-c без такой проблемы

for(int i = 0; i < array.count; i++) 
    { 
     id <Animal> an = [ar objectAtIndex:i]; 
     [an speak]; 
    } 

Так почему же это не работает в Swift?

Затем я обновил оригинальную декларацию animal1 и animal2, так это выглядит, как этот

var animal1 : Animal = Dog() 
var animal2 = Cat() 

Или я могу сделать это

var animal1 = Dog() 
    var animal2 : Animal = Cat() 

И ушла ошибка. Почему мне нужно только обновить одну из переменных, чтобы они соответствовали протоколу Animal, а не оба?

Был бы благодарен, если кто-нибудь разъяснит, что здесь происходит? Может быть, я просто не хватает что-то

Заранее спасибо

ответ

1

В быстры есть одиночное наследование (класс может наследовать только от одного класса), но множественное принятие протокола.

Тип вывода не может понять, что общего между Cat и Dog, потому что они не наследуются от одного класса. Если вы превращаете Animal в класс, ваш цикл работает отлично.

Класс может реализовывать несколько протоколов, а 2 класса могут иметь более одного протокола. Поскольку вывод типа не может выбрать один из них при определении того, какой тип назначить массиву, он выбирает его Array<AnyObject>.

Чтобы устранить эту проблему, просто сделать тип массива явный:

var ar: [Animal] = [animal1, animal2] 

animal1 и animal2, независимо от их фактического типа, являются как экземпляры классов, реализующих протокол Animal.

В этом коде:

var animal1 : Animal = Dog() 
var animal2 = Cat() 

вы обеспечиваете компилятор достаточно информации, чтобы позволить вывод типов определить тип массива: animal1 имеет Animal тип, animal2 является экземпляром Cat, который в свою очередь реализует этот протокол

+0

Objective-c также имеет множество протоколов, но не имеет этой проблемы. В качестве теста я быстро создал случайный протокол в Objc-C и добавил его в класс cat, но не для класса собаки. Однако в Obj-c я могу проверить, соответствует ли класс протоколу, можно ли что-то подобное сделать в Swift? – AdamM

+0

Вы можете проверить с помощью 'is'. Например, «если собака - это животное». Еще лучше вы можете сделать бросок, который возвращает необязательное значение, содержащее некоторое значение, если бросок был успешным или нулевым, если он не был успешным. Например, var var = arr [0] as? Dog' – Kirsteins

+1

В obj-c он работает, потому что он не использует generics, поэтому компилятор не пытается принудительно выполнить проверку типа для элементов в массиве. В быстрых случаях они должны быть одного типа или наследовать/реализовывать от общего предка. – Antonio

1

Я предполагаю, что массив причина не выводится, как Animal, потому что классы могут соответствовать нескольким протоколам, но наследовать только от одного класса. В случае, если ваши Cat и Dog также соответствуют протоколу, например Pet, откуда вы узнаете, можно ли сделать вывод о Animal или Pet массив.

В вашем случае просто объявить явный массив типа:

var ar: [Animal] = [animal1, animal2] 

for var i = 0; i < ar.count; i++ 
{ 
    var an = ar[i] 
    println(an.speak()) 
} 
0

Мы должны вывести массив как Животное, как указано выше. Пожалуйста, взгляните на это тоже

В вашем случае просто объявите явный тип arr ay:

var array: [Animal] = [animal1, animal2] 

for animal in array 
{ 
    if let an = animal is Dog { 
    print(" Hey! Dog speaking:\(an.speak())") 
    } if let an = animal is Cat { 
    print(" Hey! Cat speaking:\(an.speak())") 
    } 

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