简体   繁体   中英

Why does the Swift Compiler throw an error on inferring the type of my Generic Element when the Element is clearly constrained?

As I was working with implementing an Array that keeps weak references to its elements I stumbled on a Compile Error as soon as I used the methods of the Collection extension methods, before using the Collection method the code compiled correctly and expectedly.

Expected Behavior

The code should compile with no error.

Current Behavior

The compiler throws the two following Errors:

  1. WeakRef requires that Element? be a class type
  2. Could not infer type for 'items'

Possible Solution

The only solution I found is to make the property items public and use a for-loop instead of the Collection extensions methods. After doing this the compiler was able to infer the type for items and even the Collection methods worked.

Steps to Reproduce

First implement the WeakRef class:

final class WeakRef<T: AnyObject> {

    weak var value: T?

    init(_ value: T) {
        self.value = value
    }

}

Second implement the WeakArray struct:

struct WeakArray<Element: AnyObject> {

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

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

Third implement the Collection extension implementation:

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)
    }

}

Fourth create an instance of the WeakArray property not in the same source file however as WeakArray for example:

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

Fifth and final step call a method of the Collection protocol for example:

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

Context (Environment)

This code won't compile on the version of Xcode Version 9.3.1 (9E501) using Swift 4.1

Additional Description

The solution for the above code was found in the following links:

  1. https://marcosantadev.com/swift-arrays-holding-elements-weak-references/
  2. https://www.objc.io/blog/2017/12/28/weak-arrays/

Thank you in advance to any help provided. This post was completely edited to fit Stackoverflow standards of asking a question. Special thanks to MartinR for guiding me to post a good question on Stackoverflow.

A Collection has an associated Element type, and that seems to conflict with your generic Element placeholder. Using a different name E for the placeholder solves the problem:

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)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM