协议关联类型类型别名分配编译错误

protocol associated type typealias assignment compile error

以下代码:

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-assignment 部分(顺便说一下,这是可选的)有什么意义?

great article 确实为您提供了问题的答案。我建议大家阅读它以了解类型别名和使用它时出现的一些更高级的东西。

网站引用:

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

在这种情况下,Inttypealias 的赋值等于没有赋值,因为它被您的符合类型覆盖:

// 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

关于提供的代码示例的一些附加说明

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

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

所以协议的SomeType被推断为Double.

另一个示例,您可以看到 class 声明中的 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)
}

将被动态调度。

协议中关于“associated types”的文档中有一些重要信息。

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

在你的情况下,你使用 typealias SomeType = Int,也许你的意思是“我希望 SomeType 被限制为类似 Integer 的行为,因为我的协议方法将取决于该限制" - 在这种情况下,您可能希望在协议中使用 typealias SomeType: IntegerType,然后在 class 中继续为符合 IntegerType 的别名分配类型.

更新

在与 Apple 就此打开一个错误并围绕它进行了广泛讨论后,我开始了解基本问题的核心是什么:

当遵循协议时,您不能直接引用仅在该协议中声明的关联类型

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

因此在您的初始代码示例中:

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

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

...错误回复:"use of undeclared type" 是正确的,您的 class 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"