Swift 协议没有';不符合自己?

Swift 协议没有';不符合自己?,swift,generics,swift-protocols,Swift,Generics,Swift Protocols,为什么这个Swift代码不能编译 protocol P { } struct S: P { } let arr:[P] = [ S() ] extension Array where Element : P { func test<T>() -> [T] { return [] } } let result : [S] = arr.test() 协议P{} 结构S:P{} 设arr:[P]=[S()] 扩展数组,其中元素:P{ func

为什么这个Swift代码不能编译

protocol P { }
struct S: P { }

let arr:[P] = [ S() ]

extension Array where Element : P {
    func test<T>() -> [T] {
        return []
    }
}

let result : [S] = arr.test()
协议P{}
结构S:P{}
设arr:[P]=[S()]
扩展数组,其中元素:P{
func test()->[T]{
返回[]
}
}
let结果:[S]=阵列测试()
编译器说:“类型
p
不符合协议
p
”(或者,在更高版本的Swift中,“不支持使用'p'作为符合协议'p'的具体类型。”)


为什么不呢?不知怎么的,这感觉像是语言上的一个漏洞。我意识到问题源于将数组
arr
声明为协议类型的数组,但是这样做是不合理的吗?我认为协议的存在正是为了帮助结构提供类似类型层次结构的东西?

编辑:18个多月的工作w/Swift,另一个主要版本(提供了新的诊断),来自@AyBayBay的评论让我想重写这个答案。新的诊断是:

“不支持将“p”用作符合协议“p”的具体类型。”

这实际上让整个事情变得更清楚了。此扩展:

extension Array where Element : P {
extension Array where Element : P {
  func test<T>() -> [T] {
    return (self as [P]).test()
  }
}

let arr = [S()]
let result: [S] = arr.test()
元素==p
时不适用,因为
p
不被视为
p
的具体一致性。(下面的“放入盒子”解决方案仍然是最普遍的解决方案。)


旧答案:

这是元类型的又一个例子。斯威夫特真的希望你得到一个具体的类型为大多数非琐碎的事情<代码>[P]不是具体类型(您不能为
P
分配已知大小的内存块)。(我不认为这是真的;你完全可以创造一些大小
P
的东西,因为。)我不认为有任何证据表明这是一个“不应该”的案例。这看起来很像他们的一个“还不起作用”的案例。(不幸的是,要让苹果公司确认这两种情况之间的差异几乎是不可能的。)事实上
数组

可以是一种变量类型(其中
数组
不能),这表明他们已经在这方面做了一些工作,但Swift元类型有很多尖锐的边缘和未实现的情况。我不认为你会得到比这个更好的“为什么”答案。“因为编译器不允许。”(不满意,我知道。我的整个快速生活…)

解决办法几乎总是把东西放在盒子里。我们制作了一个打字机橡皮擦

protocol P { }
struct S: P { }

struct AnyPArray {
    var array: [P]
    init(_ array:[P]) { self.array = array }
}

extension AnyPArray {
    func test<T>() -> [T] {
        return []
    }
}

let arr = AnyPArray([S()])
let result: [S] = arr.test()
协议P{}
结构S:P{}
结构AnyPArray{
变量数组:[P]
init({array:[P]){self.array=array}
}
分机{
func test()->[T]{
返回[]
}
}
设arr=AnyPArray([S()]))
let结果:[S]=阵列测试()

当Swift允许您直接这样做时(我确实希望最终会这样),它很可能只是自动为您创建这个框。递归枚举正是这种历史。你不得不将它们框起来,这是令人难以置信的恼人和限制,最后编译器添加了
indirect
,以便更自动地完成同样的事情。

EDIT:18个多月的工作w/Swift,另一个主要版本(提供了新的诊断),来自@AyBayBay的评论让我想重写这个答案。新的诊断是:

“不支持将“p”用作符合协议“p”的具体类型。”

这实际上让整个事情变得更清楚了。此扩展:

extension Array where Element : P {
extension Array where Element : P {
  func test<T>() -> [T] {
    return (self as [P]).test()
  }
}

let arr = [S()]
let result: [S] = arr.test()
元素==p
时不适用,因为
p
不被视为
p
的具体一致性。(下面的“放入盒子”解决方案仍然是最普遍的解决方案。)


旧答案:

这是元类型的又一个例子。斯威夫特真的希望你得到一个具体的类型为大多数非琐碎的事情<代码>[P]不是具体类型(您不能为
P
分配已知大小的内存块)。(我不认为这是真的;你完全可以创造一些大小
P
的东西,因为。)我不认为有任何证据表明这是一个“不应该”的案例。这看起来很像他们的一个“还不起作用”的案例。(不幸的是,要让苹果公司确认这两种情况之间的差异几乎是不可能的。)事实上
数组

可以是一种变量类型(其中
数组
不能),这表明他们已经在这方面做了一些工作,但Swift元类型有很多尖锐的边缘和未实现的情况。我不认为你会得到比这个更好的“为什么”答案。“因为编译器不允许。”(不满意,我知道。我的整个快速生活…)

解决办法几乎总是把东西放在盒子里。我们制作了一个打字机橡皮擦

protocol P { }
struct S: P { }

struct AnyPArray {
    var array: [P]
    init(_ array:[P]) { self.array = array }
}

extension AnyPArray {
    func test<T>() -> [T] {
        return []
    }
}

let arr = AnyPArray([S()])
let result: [S] = arr.test()
协议P{}
结构S:P{}
结构AnyPArray{
变量数组:[P]
init({array:[P]){self.array=array}
}
分机{
func test()->[T]{
返回[]
}
}
设arr=AnyPArray([S()]))
let结果:[S]=阵列测试()

当Swift允许您直接这样做时(我确实希望最终会这样),它很可能只是自动为您创建这个框。递归枚举正是这种历史。你不得不把它们框起来,这是令人难以置信的恼人和限制,最后编译器添加了
间接
,以便更自动地完成同样的事情。

如果你扩展
收集类型
协议,而不是
数组
和协议约束作为具体类型,您可以按如下方式重写前面的代码

protocol P { }
struct S: P { }

let arr:[P] = [ S() ]

extension CollectionType where Generator.Element == P {
    func test<T>() -> [T] {
        return []
    }
}

let result : [S] = arr.test()
协议P{}
结构S:P{}
设arr:[P]=[S()]
扩展集合类型,其中Generator.Element==P{
func test()->[T]{
返回[]
}
}
let结果:[S]=阵列测试()

如果您扩展了
CollectionType
协议,而不是
Array
和constraint by protocol作为一个具体类型,那么您可以如下重写前面的代码

protocol P { }
struct S: P { }

let arr:[P] = [ S() ]

extension CollectionType where Generator.Element == P {
    func test<T>() -> [T] {
        return []
    }
}

let result : [S] = arr.test()
协议P{}
结构S:P{}
设arr:[P]=[S()]
扩展集合类型,其中Generator.Element==P{
func test()->[T]{
extension Array where Element == P {
  func test<T>() -> [T] {
    return []
  }
}

let arr: [P] = [S()]
let result: [S] = arr.test()
extension Array where Element : P {
  func test<T>() -> [T] {
    return (self as [P]).test()
  }
}

let arr = [S()]
let result: [S] = arr.test()
protocol P {
  var bar: Int { get set }
  func foo(str: String)
}

struct S : P {
  var bar: Int
  func foo(str: String) {/* ... */}
}

func takesConcreteP<T : P>(_ t: T) {/* ... */}

let p: P = S(bar: 5)

// error: Cannot invoke 'takesConcreteP' with an argument list of type '(P)'
takesConcreteP(p)
extension P {
  func callTakesConcreteP/*<Self : P>*/(/*self: Self*/) {
    takesConcreteP(self)
  }
}
p.callTakesConcreteP()
struct Q : P {
  var bar: Int
  func foo(str: String) {}
}

// The placeholder `T` must be satisfied by a single type
func takesConcreteArrayOfP<T : P>(_ t: [T]) {}

// ...but an array of `P` could have elements of different underlying concrete types.
let array: [P] = [S(bar: 1), Q(bar: 2)]

// So there's no sensible concrete type we can substitute for `T`.
takesConcreteArrayOfP(array) 
struct AnyP : P {

  private var base: P

  init(_ base: P) {
    self.base = base
  }

  var bar: Int {
    get { return base.bar }
    set { base.bar = newValue }
  }

  func foo(str: String) { base.foo(str: str) }
}
let p = AnyP(S(bar: 5))
takesConcreteP(p)

// example from #1...
let array = [AnyP(S(bar: 1)), AnyP(Q(bar: 2))]
takesConcreteArrayOfP(array)