Swift generi c проблема с протоколом? - PullRequest
1 голос
/ 05 апреля 2020

Я тестирую простую реализацию Swift Redux. Может ли кто-нибудь объяснить, почему вызов store.dispatch(.test) вызывает:

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

Почему невозможно разыграть AppAction to Action?, Хотя AppAction реализует протокол Action.

Middleware принимает (S, Action, (Action) -> Void), I передать его dispatch(_ action: A) в качестве 3-го параметра. это тип ((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)

1 Ответ

1 голос
/ 05 апреля 2020

Спасибо @ martin-r за подсказки. Прочитав ответ @ rob-napier: «Но параметры функции работают в обратном порядке. (String) -> Void - это супертип (Any) -> Void» по ссылкам, которые вы разместили, я переписал код ниже. Это может сэкономить время для решения той же проблемы.

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)
      }
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...