You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift执行图:协议与泛型的实现困境

类型安全实现无环执行图的节点连接

问题核心分析

你遇到的错误本质是存在类型(any NodeInput/any NodeOutput)无法直接作为泛型结构体GenericConnection的类型参数。Swift泛型系统要求参数是具有明确关联类型的具体类型,而any NodeInput是抽象的存在类型——它仅用于容纳遵循协议的实例,本身并不遵循NodeInput协议,因此无法满足泛型约束。

解决方案:兼顾统一管理与类型安全

我们可以让具体节点类同时提供两类接口:

  • 符合Node协议的inputs/outputs数组(用any类型,满足执行图的统一管理需求)
  • 暴露具体泛型类型的输入输出属性(用于类型安全的连接创建)

修改后的完整代码如下:

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

// 基础输入输出实现
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
    }
}

// 修改后的ConstantColorNode
class ConstantColorNode: Node {
    let inputs: [any NodeInput] = []
    private(set) var outputs: [any NodeOutput] = []
    
    public private(set) var color: UIColor {
        didSet {
            colorOutput.value = color
        }
    }
    
    // 直接暴露具体类型的输出属性
    let colorOutput: SimpleNodeOutput<UIColor>
    
    public init(color: UIColor) {
        self.color = color
        colorOutput = SimpleNodeOutput(value: color)
        outputs = [colorOutput]
    }
    
    func set(color: UIColor) {
        self.color = color
    }
}

// 修改后的FinalOutputNode
class FinalOutputNode<T>: Node {
    private(set) var inputs: [any NodeInput] = []
    let outputs: [any NodeOutput] = []
    
    // 直接暴露具体类型的输入属性
    let finalInput: SimpleNodeInput<T>
    
    init(initialValue: T) {
        finalInput = SimpleNodeInput(value: initialValue)
        inputs = [finalInput]
    }
}

// 类型安全地创建连接
let colorNode = ConstantColorNode(color: .red)
let outputNode = FinalOutputNode<UIColor>(initialValue: .blue)
do {
    let genericConnection = try GenericConnection(input: outputNode.finalInput, output: colorNode.colorOutput)
    try genericConnection.activate()
    print(outputNode.finalInput.value) // 输出 UIColor.red
} catch {
    print("连接失败:\(error)")
}

方案优势

  • 编译期类型安全:完全避免运行时类型检查和Any类型,类型不匹配的错误会在编译阶段被捕获
  • 统一管理兼容:Node协议的inputs/outputs依然支持用any类型存储,方便将所有节点纳入执行图统一管理
  • 接口直观清晰:具体节点的输入输出属性明确标注类型,调用方可以直接感知可连接的类型范围

扩展:动态场景下的通用连接工具

如果需要从Node协议的inputs/outputs数组中动态获取实例并创建连接,可以封装泛型工具函数,通过条件转型保证类型安全:

enum ConnectionError: Error {
    case typeMismatch
    case invalidInput
    case invalidOutput
}

func createConnection<T>(input: any NodeInput, output: any NodeOutput) throws -> GenericConnection<SimpleNodeInput<T>, SimpleNodeOutput<T>> {
    guard let typedInput = input as? SimpleNodeInput<T>,
          let typedOutput = output as? SimpleNodeOutput<T> else {
        throw ConnectionError.typeMismatch
    }
    return try GenericConnection(input: typedInput, output: typedOutput)
}

// 使用示例
do {
    let dynamicInput = outputNode.inputs.first!
    let dynamicOutput = colorNode.outputs.first!
    let connection = try createConnection(input: dynamicInput, output: dynamicOutput)
} catch {
    print(error)
}

内容的提问来源于stack exchange,提问作者Joshua Sullivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 20:15:59