我正在尝试做一些我认为应该非常简单的事情,但是我在 Swift 的类型推断方面遇到了麻烦。我真的不明白为什么会掉在这里。
我有一个类型
Cocktail
,它还有其他属性,但这里唯一重要的是 name
:
struct Cocktail {
// ... other stuff
let name: String
}
然后我有两个协议:
protocol ScrollIndexable {
var scrollIndexTitle: String { get }
}
protocol ScrollIndexProviding {
var scrollIndices: [any ScrollIndexable] { get }
}
以及
String
到 ScrollIndexable
的简单一致性:
extension String: ScrollIndexable {
var scrollIndexTitle: String { self }
}
我想这样做,以便我可以使用一组
Cocktail
作为 ScrollIndexProviding
:
extension Array: ScrollIndexProviding where Element == Cocktail {
var scrollIndices: [any ScrollIndexable] {
let firstCharacters = reduce(into: Set<String>()) { partialResult, cocktail in
guard let firstCharacter = cocktail.name.first else {
return
}
partialResult.insert(String(firstCharacter))
}
// The return line here has two errors:
// Cannot convert return expression of type 'Array<Cocktail>' to return type '[any ScrollIndexable]'
// No exact matches in call to initializer
return Array(firstCharacters)
}
}
此扩展无法构建,有两个错误:
第二个错误对我来说似乎是噪音,因为
Set
符合 Sequence
,所以我应该能够使用该 init 方法。
第一个错误让我感到困惑,因为
firstCharacters
数组的类型是 Set<String>
,所以错误消息似乎没有任何意义。我对这里的 any
关键字有什么误解吗?发生什么事了?
问题是您位于
Array
的扩展中,其中 Element
是 Cocktail
,因此当您尝试创建数组而不指定元素类型时,编译器会假设您的意思是元素类型为Cocktail
。
extension Array where Element == Cocktail {
func someMethod() {
// This array is of type `Array<Cocktail>` since the compiler
// assumes the array's element type should be the same as
// Self's element type, which (from the extension) is `Cocktail`.
let array = Array()
}
}
因此,要解决此问题,只需显式告诉编译器数组的元素类型是 String,如下所示:
extension Array: ScrollIndexProviding where Element == Cocktail {
var scrollIndices: [any ScrollIndexable] {
let firstCharacters = reduce(into: Set<String>()) { partialResult, cocktail in
guard let firstCharacter = cocktail.name.first else {
return
}
partialResult.insert(String(firstCharacter))
}
return Array<String>(firstCharacters)
// ^^^^^^^^ add this
}
}