简体   繁体   中英

How a generic class to conform a protocol (that have init in it) with constraint?

Sorry for all these protocol mess. I provide it for the sake of code completeness. The question is actually about the last chunk of the code at the bottom.

protocol Edgedable: Hashable {
    associatedtype Edge: Destinationable
    var edges: Set<Edge> { get set }
}

protocol Destinationable: Hashable {
    associatedtype D: Hashable
    var destination: D { get set }
}

class Graph<Node: Edgedable>: ExpressibleByDictionaryLiteral {
    typealias Edge = Node.Edge
    typealias D = Edge.D
    private var storage: [D: Node]
    
    init(_ tuples: [(D, Node)]) {
        self.storage = .init(uniqueKeysWithValues: tuples)
        // Some PostInit code here
    }

    required convenience init(dictionaryLiteral elements: (D, Node)...) {
        self.init(elements)
    }
}

extension Graph: ExpressibleByArrayLiteral where D == Int {
    
    required convenience init(arrayLiteral elements: Node...) {
        self.init(Array(zip(0..., elements)))
    }
}

I choose a standard approach here: via extension. It looks like exactly what I need. That is the class implements the protocol only in the case of D == Int But the code doesn't compile:

'required' initializer must be declared directly in class 'Graph' (not in an extension)

Initializer requirement 'init(arrayLiteral:)' can only be satisfied by a 'required' initializer in the definition of non-final class 'Graph'

Okey, I can declare it directly in class, exactly like I did with another init (and another corresponding protocol). But how to set the constraint!?

class Graph<Node: Edgedable>: ExpressibleByDictionaryLiteral, ExpressibleByArrayLiteral where Node.Edge.D == Int {

This is not correct. This declaration has a different meaning. Not that I'm trying to achieve.

I don't know of a way to achieve this without making Graph final . If you do make it final , however, it will work fine as long as you remove required ( required doesn't mean anything if there can't be subclasses):

extension Graph: ExpressibleByArrayLiteral where D == Int {
    convenience init(arrayLiteral elements: Node...) {
        self.init(Array(zip(0..., elements)))
    }
}

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