如何为可选类型的NavigationRoute实现Publisher的sinkWithActions扩展?
问题原因
你的扩展约束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
相关产品推荐
相关产品推荐

