2015-07-22 3 views
7

После кода:протокол, связанный тип присвоения typealias ошибки компиляции

protocol SomeProtocol { 
    typealias SomeType = Int // used typealias-assignment 

    func someFunc(someVar: SomeType) 
} 

class SomeClass: SomeProtocol { 
    func someFunc(someVar: SomeType) { 
     print(someVar) 
    } 
} 

дает время компиляции ошибка:

Use of undeclared type 'SomeType'

Добавление, скажем typealias SomeType = Double, к SomeClass устраняет ошибку.

Вопрос в том, что имеет смысл typealias-присваивание часть (которая необязательна кстати) протокола ассоциированного типа объявления хотя?

ответ

5

В этом случае назначение Int к typealias равно не присваивания, поскольку он получает переопределены вашего типа конформного:

// this declaration is equal since you HAVE TO provide the type for SomeType 
protocol SomeProtocol { 
    typealias SomeType 

    func someFunc(someVar: SomeType) 
} 

Такое задание обеспечивает тип по умолчанию для SomeType, который переопределяется вашей реализацией в SomeClass, но он особенно полезен для расширений протокола:

protocol Returnable { 
    typealias T = Int // T is by default of type Int 
    func returnValue(value: T) -> T 
} 

extension Returnable { 
    func returnValue(value: T) -> T { 
     return value 
    } 
} 

struct AStruct: Returnable {} 

AStruct().returnValue(3) // default signature: Int -> Int 

Вы получаете эту функцию бесплатно только в соответствии с протоколом, не указав тип T. Если вы хотите установить свой собственный тип, напишите typealias T = String // or any other type в структуре struct.

Некоторые дополнительные замечания о поставленном примере кода

Вы решили эту проблему, так как вы сделали это явно, какой тип параметра имеет. Swift также выводит ваш используемый тип:

class SomeClass: SomeProtocol { 
    func someFunc(someVar: Double) { 
     print(someVar) 
    } 
} 

Так SomeType протокола выводится как Double.

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

class SomeClass: SomeProtocol { 
    typealias Some = Int 
    func someFunc(someVar: Some) { 
     print(someVar) 
    } 
} 

// check the type of SomeType of the protocol 
// dynamicType returns the current type and SomeType is a property of it 
SomeClass().dynamicType.SomeType.self // Int.Type 
// SomeType gets inferred form the function signature 

Однако, если вы делаете что-то вроде этого:

protocol SomeProtocol { 
    typealias SomeType: SomeProtocol 

    func someFunc(someVar: SomeType) 
} 

SomeType должен иметь тип SomeProtocol, который может использоваться для более четкой абстракции и более статического кода, тогда как это:

protocol SomeProtocol { 
    func someFunc(someVar: SomeProtocol) 
} 

будет динамически отправляться.

+0

Слушайте, я не просил кого-нибудь ответить, почему объявление титалий внутри класса разрешает ошибку. Я понял, что до того, как я создал эту тему. Я спросил, что такое практическое применение назначения типов в протоколе. Перефразируя, какие конкретные ограничения решаются этой функцией? – mesmerizingr

+0

@mesmerizingsnow Это была дополнительная информация. Но я также дал ответ: присваивание не влияет на поведение, как отсутствие назначения ('typealias SomeType = Int' равно' typealias SomeType') – Qbyte

+0

Я получил этот ответ эмпирически. У вас есть что-то, чтобы поддержать ваш ответ, скажем, ссылки на форумы developer.apple.com или некоторые цитаты из какого-то блога, твиттера или что-то еще? – mesmerizingr

1

Существует great article, что фактически дает вам ответ на ваш вопрос. Я предлагаю всем прочитать его, чтобы попасть в псевдонимы типов и некоторые более продвинутые вещи, которые появляются, когда вы его используете.

Цитирование с сайта:

Conceptually, there is no generic protocols in Swift. But by using typealias we can declare a required alias for another type.

+0

В статье они не использовали назначение typealias. Они использовали предложение наследования типа, хотя это не отвечает на мой вопрос. – mesmerizingr

5

В документации по протоколу "associated types" имеется подробная информация.

Их использование в изобилии по всей стандартной библиотеки, для примера ссылки на протокол SequenceType, который объявляет typealias для Generator (и указывает, что оно соответствует GeneratorType). Это позволяет объявлению протокола ссылаться на этот псевдонимов.

В вашем случае, когда вы использовали typealias SomeType = Int, возможно, что вы имели в виду был «Я хочу SomeType быть ограничен в Integer-подобного поведения, потому что мои методы протокола будет зависеть от этого ограничения» - в этом случае, вы можете захотеть использовать в своем протоколе typealias SomeType: IntegerType, а затем в своем классе перейти к назначению типа для этого псевдонима, который соответствует IntegerType.

UPDATE

После открытия ошибки ж/Apple, на этом и имел широкое обсуждение вокруг него, я пришел к пониманию того, что базовая проблема лежит в основе этого:

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

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

Так что в вашем исходном примере кода:

protocol SomeProtocol { 
    typealias SomeType = Int 
    func someFunc(someVar: SomeType) 
} 

class SomeClass: SomeProtocol { 
    func someFunc(someVar: SomeType) { // use of undeclared type "SomeType" 
     print(someVar) 
    } 
} 

... повторная ошибка: «Использование необъявленной типа»правильно, ваш класс SomeClass не объявлен типа SomeType

Однако расширение SomeProtocol имеет доступ к связанному типу и может относиться к нему, когда обеспечивая выполнение:

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

protocol SomeProtocol { 
    typealias SomeType = Int 
    func someFunc(someVar: SomeType) 
} 

extension SomeProtocol where SomeType == Int { 
    func someFunc(someVar: SomeType) { 
     print("1 + \(someVar) = \(1 + someVar)") 
    } 
} 

class SomeClass: SomeProtocol {} 

SomeClass().someFunc(3) // => "1 + 3 = 4" 
+0

В моем случае я использовал назначение «Int», чтобы проверить эту функциональность. Я сидел со своим ноутбуком, читал «Справочник по языку» официального справочника Apple «Swift Programming Guide», попал в раздел «Декларация» и нашел ссылку на объявление протокола со ссылкой на синтаксис объявления соответствующего типа. И там я обнаружил, что при объявлении typealiases можно использовать назначение typealias. Хотя это необязательно. – mesmerizingr

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