协议关联类型typealias赋值编译错误

时间:2015-07-22 11:49:53

标签: swift swift2 protocols

以下代码:

typealias SomeType = Double

给出了编译时错误:

  

使用未声明的类型' SomeType'

SomeClass添加$('.menucircle'),可以解决错误。

问题是,协议相关类型声明的 typealias-assignment 部分(可选btw)的重点是什么?

3 个答案:

答案 0 :(得分: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的类型才能免费获得该功能。如果要在结构体中设置自己的类型write typealias T = String // or any other type

有关提供的代码示例的一些其他说明

您解决了这个问题,因为您明确了该参数的类型。 Swift还会推断您使用过的类型:

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

因此推断协议SomeTypeDouble

另一个例子,你可以看到类声明中的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)
}

将动态调度。

答案 1 :(得分:5)

协议中的“associated types”文档中有一些很好的信息。

它们在整个标准库中的使用非常丰富,例如参考SequenceType协议,该协议为typealias声明Generator(并指定它符合GeneratorType )。这允许协议声明引用该别名类型。

在你使用typealias SomeType = Int的情况下,或许你的意思是“我希望SomeType被约束为类似Integer的行为,因为我的协议方法将依赖于那个约束” - 在这种情况下,您可能希望在协议中使用typealias SomeType: IntegerType,然后在您的班级中继续为该别名指定符合IntegerType的类型。

<强>更新

在打开苹果公司的一个错误之后,围绕它进行了广泛的讨论,我已经了解了基础问题的核心是什么:

符合协议时,您无法直接引用仅在该协议中声明的关联类型

(请注意,当扩展协议时,关联类型可用,如您所料)

所以在你的初始代码示例中:

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"

答案 2 :(得分:1)

great article实际上可以为您的问题提供答案。我建议大家阅读它以进入类型别名和一些更高级的东西,当你使用它时。

来自网站的引文:

  

从概念上讲,Swift中没有通用协议。但通过使用   typealias我们可以为另一个类型声明一个必需的别名。