为什么这段 Swift 代码会引发类型检查错误?我使用的是 Swift 5。

huangapple go评论70阅读模式
英文:

Why this swift code cause type-checking error? I'm in Swift 5

问题

这是一段Swift测试代码的片段,为什么它不起作用?如何使其正常工作?

import UIKit

class SwiftTestController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        test()
    }
    
    func test() {
        let resourceViews: Array<any ResourceView> = []
        // 此行出现类型检查错误。
        let resources = resourceViews.map { $0.resource }
    }
}

protocol ResourceComponent {
    
}

// 正常工作
protocol ResourceView: ResourceComponent {
    associatedtype R: Resource
    var resource: R { get set }
}

// 不起作用
//protocol ResourceView: UIView, ResourceComponent {
//    associatedtype R: Resource
//    var resource: R { get set }
//}

// 不起作用
//protocol ResourceView: UIView {
//    associatedtype R: Resource
//    var resource: R { get set }
//}

protocol Resource {}

以下是详细错误消息的图像!

![图片描述][1]

`ResourceView` 不继承(约束于)`UIView` 时可以正常工作。

我已经提交了一个[问题报告][2]

  [1]: https://i.stack.imgur.com/M2o7b.png
  [2]: https://github.com/apple/swift/issues/63933

<details>
<summary>英文:</summary>

Here&#39;s a snippet of swift test code, why this does not working? How to make it working?

    import UIKit
    
    class SwiftTestController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            test()
        }
        
        func test() {
            let resourceViews: Array&lt;any ResourceView&gt; = []
           // type-checking error in this line.
            let resources = resourceViews.map { $0.resource }
        }
    }
    
    
    protocol ResourceComponent {
        
    }
    
    // fine
    protocol ResourceView: ResourceComponent {
        associatedtype R: Resource
        var resource: R { get set }
    }
    
    // does not working
    //protocol ResourceView: UIView, ResourceComponent {
    //    associatedtype R: Resource
    //    var resource: R { get set }
    //}
    
    // does not working
    //protocol ResourceView: UIView {
    //    associatedtype R: Resource
    //    var resource: R { get set }
    //}
    
    protocol Resource {}

Below is a image for detail error message!
[![enter image description here][1]][1]


let `ResourceView` does not inherit(constraint to) `UIView` works fine.

I&#39;ve submitted a [issue][2].


  [1]: https://i.stack.imgur.com/M2o7b.png
  [2]: https://github.com/apple/swift/issues/63933

</details>


# 答案1
**得分**: 2

这显然是问题[#63751][2]

根据错误报告,这是[SE-309 解锁所有协议的存在性][3]的未实现部分,每当您打开一个同时也是l值的存在性时,比如一个类绑定的协议类型,就会发生这种情况。

无论如何,我发现将`resourceViews`声明为`ResourceView``UIView`之间的交集类型可以工作:

```swift
protocol ResourceView:  ResourceComponent { // 删除类绑定
    ...
}

let resourceViews: Array<ResourceView & UIView> = []

map 行上的类型约束在这里实际上几乎是相同的(我认为),但不知何故 Swift 对此感到满意。

当然,这里的不同之处在于非UIView现在可以符合ResourceView,但归根结底,它们无法进入resourceViews数组,所以我认为这可能是一个可行的解决方案。在您的情况下,还有一些更小的差异,我认为这不太重要,可以在这里找到答案。

也许稍微改一下命名也会有所帮助 为什么这段 Swift 代码会引发类型检查错误?我使用的是 Swift 5。

protocol ResourceComponent {
    
}

protocol ResourceBox:  ResourceComponent {
    associatedtype R: Resource
    var resource: R { get set }
}

protocol Resource {
    
}

typealias ResourceView = any ResourceBox & UIView

let resourceViews: Array<ResourceView> = []
英文:

This is apparently issue #63751

According to the bug report, this is an unimplemented part of SE-309 Unlock existentials for all protocols, and happens whenever you open an existential that is also an l-value, like a class-bound protocol type.

Anyway, I've found that declaring resourceViews to be an intersection type between ResourceView and UIView to work:

protocol ResourceView:  ResourceComponent { // remove the class bound
...
}
let resourceViews: Array&lt;any ResourceView &amp; UIView&gt; = []

The type constraints on the map line are practically the same here (I think), but somehow Swift is happy with this.

The difference here is of course that non-UIViews can now conform to ResourceView, but at the end of the day they can't go in the resourceViews array, so I think this could be a viable solution for now. There are a few more minor differences that I don't think matters too much in your case, which is answered here.

Maybe a bit of renaming would also help 为什么这段 Swift 代码会引发类型检查错误?我使用的是 Swift 5。

protocol ResourceComponent {
}
protocol ResourceBox:  ResourceComponent {
associatedtype R: Resource
var resource: R { get set }
}
protocol Resource {
}
typealias ResourceView = any ResourceBox &amp; UIView
let resourceViews: Array&lt;ResourceView&gt; = []

huangapple
  • 本文由 发表于 2023年2月27日 15:42:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75577848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定