我正在尝试创建一个由节点组成的通用非循环执行图。每个节点有 0 个或多个输入和输出。每个输入和输出都针对特定对象类型(Double、UIImage、String 等)进行类型化。我希望只能以一对一的关系(无复用)连接具有匹配对象类型的输入和输出。一切都正常,直到我尝试创建 Connection 对象,该对象表示不同节点上的特定输入和输出之间存在连接。以下是我的类型的简化版本:
import UIKit
protocol NodeOutput {
associatedtype Entity
var type: Entity.Type { get }
var value: Entity { get }
}
protocol NodeInput {
associatedtype Entity
var type: Entity.Type { get }
func set(value: Entity)
}
protocol Node {
var inputs: [any NodeInput] { get }
var outputs: [any NodeOutput] { get }
}
struct GenericConnection<Input: NodeInput, Output: NodeOutput> where Input.Entity == Output.Entity {
public let input: Input
public let output: Output
/// Create a new connection object.
public init(input: Input, output: Output) throws {
self.input = input
self.output = output
input.set(value: output.value)
}
public func activate() throws {
input.set(value: output.value)
}
}
// Actual Implementations
class SimpleNodeInput<Entity>: NodeInput {
public var type: Entity.Type { Entity.self }
public private(set) var value: Entity
public init(value: Entity) {
self.value = value
}
public func set(value: Entity) {
self.value = value
}
}
class SimpleNodeOutput<Entity>: NodeOutput {
public var type: Entity.Type { Entity.self }
public var value: Entity
public init(value: Entity) {
self.value = value
}
}
class ConstantColorNode: Node {
let inputs: [any NodeInput] = []
private(set) var outputs: [any NodeOutput] = []
public private(set) var color: UIColor {
didSet {
_colorOutput.value = color
}
}
private var _colorOutput: SimpleNodeOutput<UIColor>
var colorOutput: any NodeOutput { _colorOutput as any NodeOutput }
public init(color: UIColor) {
self.color = color
_colorOutput = SimpleNodeOutput(value: color)
self.outputs = [colorOutput]
}
func set(color: UIColor) {
self.color = color
}
}
class FinalOutputNode<T>: Node {
private(set) var inputs: [any NodeInput] = []
let outputs: [any NodeOutput] = []
var finalInput: any NodeInput
init(initialValue: T) {
finalInput = SimpleNodeInput(value: initialValue)
self.inputs = [finalInput]
}
}
let colorNode = ConstantColorNode(color: .red)
let outputNode = FinalOutputNode<UIColor>(initialValue: .blue)
let genericConnection = try GenericConnection(input: outputNode.finalInput, output: colorNode.colorOutput)
所以... Connection 类型有一个编译器错误,即
set
不能在类型 any NodeInput
上使用。 GenericConnection 类型不会出现编译器错误,直到您尝试实例化它,然后您会收到错误:any NodeInput
不符合 NodeInput
和 any NodeOutput
不符合 NodeOutput
。
我真的不确定如何对需要限制为具有相同泛型类型的节点之间的连接进行建模。作为记录,我有多个输入和输出节点类型,它们可以执行诸如发出常量值或查询委托的类型和值之类的操作。只是不确定如何正确地做到这一点,或者是否可以优雅地表达而不需要制作所有数据
Any
然后进行运行时类型检查(这看起来超级恶心)。
您可以使用主要关联类型:
protocol NodeOutput<Entity> {
associatedtype Entity
var type: Entity.Type { get }
var value: Entity { get }
}
protocol NodeInput<Entity> {
associatedtype Entity
var type: Entity.Type { get }
func set(value: Entity)
}
protocol Node<Entity> {
associatedtype Entity
var inputs: [any NodeInput<Entity>] { get }
var outputs: [any NodeOutput<Entity>] { get }
}
struct GenericConnection<T> {
public let input: any NodeInput<T>
public let output: any NodeOutput<T>
/// Create a new connection object.
public init(input: any NodeInput<T>, output: any NodeOutput<T>) throws {
self.input = input
self.output = output
input.set(value: output.value)
}
public func activate() throws {
input.set(value: output.value)
}
}
// Actual Implementations
class SimpleNodeInput<Entity>: NodeInput {
public var type: Entity.Type { Entity.self }
public private(set) var value: Entity
public init(value: Entity) {
self.value = value
}
public func set(value: Entity) {
self.value = value
}
}
class SimpleNodeOutput<Entity>: NodeOutput {
public var type: Entity.Type { Entity.self }
public var value: Entity
public init(value: Entity) {
self.value = value
}
}
class ConstantColorNode: Node {
let inputs: [any NodeInput<UIColor>] = []
private(set) var outputs: [any NodeOutput<UIColor>] = []
public private(set) var color: UIColor {
didSet {
_colorOutput.value = color
}
}
private var _colorOutput: SimpleNodeOutput<UIColor>
var colorOutput: any NodeOutput<UIColor> { _colorOutput as any NodeOutput<UIColor> }
public init(color: UIColor) {
self.color = color
_colorOutput = SimpleNodeOutput(value: color)
self.outputs = [colorOutput]
}
func set(color: UIColor) {
self.color = color
}
}
class FinalOutputNode<T>: Node {
private(set) var inputs: [any NodeInput<T>] = []
let outputs: [any NodeOutput<T>] = []
var finalInput: any NodeInput<T>
init(initialValue: T) {
finalInput = SimpleNodeInput(value: initialValue)
self.inputs = [finalInput]
}
}
struct ConnectionBundle {
public let input: any NodeInput
public let output: any NodeOutput
init(input: any NodeInput, output: any NodeOutput) {
self.input = input
self.output = output
}
}
let colorNode = ConstantColorNode(color: .red)
let outputNode = FinalOutputNode<UIColor>(initialValue: .blue)
let genericConnection = try GenericConnection(input: outputNode.finalInput, output: colorNode.colorOutput)