当元素明显受限时,为什么Swift编译器会在推断我的通用元素类型时抛出错误?

时间:2018-05-23 12:03:18

标签: arrays swift generics compiler-errors

当我正在使用实现一个保持对其元素的弱引用的Array时,在使用Collection扩展方法的方法之前,我偶然发现了编译错误,然后才使用Collection方法代码编译正确且预期。

预期行为

代码应该编译没有错误。

当前行为

编译器抛出以下两个错误:

  1. WeakRef需要Element吗?是一个班级类型
  2. 无法推断'项目'
  3. 的类型

    可能的解决方案

    我找到的唯一解决方案是将属性项公开,并使用for循环而不是Collection扩展方法。执行此操作后,编译器能够推断items的类型,甚至Collection方法的工作方式。

    重现步骤

    首先实现WeakRef类:

    final class WeakRef<T: AnyObject> {
    
        weak var value: T?
    
        init(_ value: T) {
            self.value = value
        }
    
    }
    

    第二次实现WeakArray结构:

    struct WeakArray<Element: AnyObject> {
    
        public var items: [WeakRef<Element>] = []
    
        init(_ elements: [Element]) {
            items = elements.map { WeakRef($0) }
        }
    }
    

    第三次实施Collection扩展实施:

    extension WeakArray: Collection {
    
        var startIndex: Int { return items.startIndex }
        var endIndex: Int { return items.endIndex }
    
        subscript(_ index: Int) -> Element? {
            return items[index].value
        }
    
        func index(after idx: Int) -> Int {
            return items.index(after: idx)
        }
    
    }
    

    第四个创建WeakArray属性的实例,不是在同一个源文件中,而是创建WeakArray,例如:

    var objects: WeakArray<UIViewController> = WeakArray.init([])
    

    第五步也是最后一步调用Collection协议的方法,例如:

    objects.forEach({ $0?.view.backgroundColor = .white })
    

    上下文(环境)

    此代码不会使用Swift 4.1在Xcode版本9.3.1(9E501)的版本上进行编译

    附加说明

    上述代码的解决方案可在以下链接中找到:

    1. https://marcosantadev.com/swift-arrays-holding-elements-weak-references/
    2. https://www.objc.io/blog/2017/12/28/weak-arrays/
    3. 提前感谢您提供的任何帮助。这篇文章经过全面编辑,符合Stackoverflow提出问题的标准。特别感谢MartinR指导我在Stackoverflow上发布一个好问题。

1 个答案:

答案 0 :(得分:2)

Collection有一个关联的Element类型,似乎就是这样 与您的通用Element占位符冲突。使用不同的 占位符的名称E解决了问题:

struct WeakArray<E: AnyObject> {

    public var items: [WeakRef<E>] = []

    init(_ elements: [E]) {
        items = elements.map { WeakRef($0) }
    }
}

extension WeakArray: Collection {

    var startIndex: Int { return items.startIndex }
    var endIndex: Int { return items.endIndex }

    subscript(_ index: Int) -> E? {
        return items[index].value
    }

    func index(after idx: Int) -> Int {
        return items.index(after: idx)
    }
}