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

如何为可选类型的NavigationRoute实现Publisher的sinkWithActions扩展?

解决可选类型NavigationRoute的Publisher扩展编译错误

问题原因

你的扩展约束where Output: NavigationRoute只接受直接遵守NavigationRoute协议的类型,但Optional<DetailsRoute>本身并没有遵守该协议——尽管DetailsRoute符合要求,但Optional容器类型并没有实现NavigationRoute的相关要求(Identifiable和Equatable的合成逻辑不会自动让Optional遵守该协议)。

解决方案

下面提供两种可行的解决方式,你可以根据需求选择:

方案一:新增针对可选路由类型的扩展

直接为输出类型是Optional<Route>(其中Route遵守NavigationRoute)的Publisher添加扩展,和原有非可选类型的扩展共存:

protocol NavigationRoute: Identifiable, Equatable { }

struct DetailsRoute: NavigationRoute {
    var id: Int
}

final class ViewModel: ObservableObject {
    @Published var fullscreen: DetailsRoute?
    private var cancellables = Set<AnyCancellable>()

    init() {
        $fullscreen
            .sinkWithActions()
            .store(in: &cancellables)
    }
}

// 处理非可选NavigationRoute的情况
extension Publisher where Output: NavigationRoute, Failure == Never {
    func sinkWithActions() -> AnyCancellable {
        self.sink { route in
            // 自定义操作:处理非可选路由
            print("Received non-optional route: \(route)")
        }
    }
}

// 处理可选NavigationRoute的情况
extension Publisher where Output == Optional<Route>, Route: NavigationRoute, Failure == Never {
    func sinkWithActions() -> AnyCancellable {
        self.sink { optionalRoute in
            // 自定义操作:处理可选路由
            if let route = optionalRoute {
                print("Received optional route: \(route)")
            } else {
                print("Route is nil")
            }
        }
    }
}

方案二:通过自定义协议兼容所有可选类型

如果需要支持更多泛型场景,可以定义一个OptionalType协议来统一处理所有可选输出,避免重复编写扩展:

protocol NavigationRoute: Identifiable, Equatable { }

// 定义可选类型协议
protocol OptionalType {
    associatedtype Wrapped
    var wrappedValue: Wrapped? { get }
}

// 让Optional遵守该协议
extension Optional: OptionalType {
    var wrappedValue: Wrapped? { self }
}

struct DetailsRoute: NavigationRoute {
    var id: Int
}

final class ViewModel: ObservableObject {
    @Published var fullscreen: DetailsRoute?
    private var cancellables = Set<AnyCancellable>()

    init() {
        $fullscreen
            .sinkWithActions()
            .store(in: &cancellables)
    }
}

// 同时支持非可选和可选的NavigationRoute输出
extension Publisher where Failure == Never {
    func sinkWithActions() -> AnyCancellable where Output: NavigationRoute {
        self.sink { route in
            print("Received non-optional route: \(route)")
        }
    }

    func sinkWithActions() -> AnyCancellable where Output: OptionalType, Output.Wrapped: NavigationRoute {
        self.sink { output in
            if let route = output.wrappedValue {
                print("Received optional route: \(route)")
            } else {
                print("Route is nil")
            }
        }
    }
}

说明

两种方案都能解决编译错误,方案一更直观,适合只需要处理特定可选路由的场景;方案二更灵活,能自动适配所有符合条件的可选类型输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:28:24