英文:
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'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<any ResourceView> = []
// 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'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
数组,所以我认为这可能是一个可行的解决方案。在您的情况下,还有一些更小的差异,我认为这不太重要,可以在这里找到答案。
也许稍微改一下命名也会有所帮助
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<any ResourceView & UIView> = []
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-UIView
s 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
protocol ResourceComponent {
}
protocol ResourceBox: ResourceComponent {
associatedtype R: Resource
var resource: R { get set }
}
protocol Resource {
}
typealias ResourceView = any ResourceBox & UIView
let resourceViews: Array<ResourceView> = []
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论