【问题标题】:Swift generic protocol issue?Swift 通用协议问题?
【发布时间】:2020-04-05 15:23:05
【问题描述】:

我正在测试一个简单的 Swift Redux 实现。有人可以解释为什么打电话 store.dispatch(.test) 原因:

Could not cast value of type '(Test.AppAction) -> ()' to '(Test.Action) -> ()'.

为什么不能将 AppAction 强制转换为 Action?虽然 AppAction 实现了 Action 协议。

中间件接受(S, Action, (Action) -> Void), 我将dispatch(_ action: A) 作为第三个参数传递。这是((Action) -> Void)的一种类型,但它不能接受。

protocol State {}
protocol Action {}

typealias Reducer<S: State, A: Action> = (S, A) -> S
typealias Dispatcher = (Action) -> Void
typealias Middleware<S: State> = (S, Action, @escaping Dispatcher) -> Void

protocol Store: ObservableObject {
   associatedtype S: State
   associatedtype A: Action

   func dispatch(action: A)
}

final class DefaultStore<S: State, A: Action>: ObservableObject {
   @Published private(set) var state: S

   private let reducer: Reducer<S, A>
   private let middlewares: [Middleware<S>]

   init(initialState: S, reducer: @escaping Reducer<S, A>, middlewares: [Middleware<S>] = []) {
      self.state = initialState
      self.reducer = reducer
      self.middlewares = middlewares
   }

   func dispatch(_ action: A) {
      state = reducer(state, action)

      middlewares.forEach { middleware in
         middleware(state, action, dispatch as! Dispatcher)
      }
   }
}

// START

struct AppState: State { }
enum AppAction: Action { // A test action to have smthg. to call
   case test
}

let appReducer: Reducer<AppState, AppAction> = { s, a in s }
let middleware: Middleware<AppState> = { s, a, dispatch in }

var store = DefaultStore(initialState: AppState(), reducer: appReducer, middlewares: [middleware])
store.dispatch(.test)

【问题讨论】:

  • 我在 11.4 上试过,它编译正确,但是当你调用 store.dispatch(.test) 时它崩溃了。在 XCode 中制作一个命令行应用,粘贴 sn-p 并运行测试。
  • 您可以将AppAction 转换为Action,但不能将((AppAction)) -&gt; () 转换为((Action) -&gt; ())。参见例如medium.com/@aunnnn/…
  • 另见stackoverflow.com/a/35700892/1187415“正式地说,函数的参数是逆变的,返回值是协变的。”

标签: swift generics redux swift-protocols


【解决方案1】:

感谢@martin-r 提供线索。在阅读@rob-napier 答案后:“但函数参数以相反的顺序工作。(字符串)-> Void 是(任何)-> Void 的超类型”从您发布的链接中,我将代码重写为 sn-p 波纹管.它可能会节省处理相同问题的人的时间。

protocol State {}
protocol Action {}

typealias Reducer<S: State, A: Action> = (S, A) -> S
typealias Dispatcher<A: Action> = (A) -> Void
typealias Middleware<S: State, A: Action> = (S, A, (A) -> Void) -> Void

protocol Store: ObservableObject {
   associatedtype S: State
   associatedtype A: Action

   func dispatch(action: A)
}

final class DefaultStore<S: State, A: Action>: ObservableObject {
   @Published private(set) var state: S

   private let reducer: Reducer<S, A>
   private let middlewares: [Middleware<S, A>]

   init(initialState: S, reducer: @escaping Reducer<S, A>, middlewares: [Middleware<S, A>] = []) {
      self.state = initialState
      self.reducer = reducer
      self.middlewares = middlewares
   }

   func dispatch(_ action: A) {
      state = reducer(state, action)

      middlewares.forEach { middleware in
         middleware(state, action, dispatch)
      }
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多