代码之家  ›  专栏  ›  技术社区  ›  john doe

关联类型Swift的约束

  •  0
  • john doe  · 技术社区  · 4 年前

    Swift不允许对泛型施加关联类型的约束吗。

    typealias Reducer = (State, Action) -> State
    
    class RootReducer {
        
        var reducers: [Reducer] = [Reducer]()
        
        func addReducer<T: Reducer>(_ reducer: T) {
            self.reducers.append(reducer)
        }
    }
    

    我得到以下结果:

    enter image description here

    更新:

    我如何传递类型并将类型存储为字典的键,而不是将名称用作字符串。

    typealias Reducer = (State, Action) -> State
    
    class RootReducer {
        
        var reducers: [String :Reducer] = [:]
        
        func addReducer(name: String, reducer: @escaping Reducer) {
            reducers[name] = reducer
        }
    }
    
    0 回复  |  直到 4 年前
        1
  •  2
  •   Sulthan    4 年前

    从技术上讲,这不是对你具体问题的回答,但无论如何都会有所帮助。我觉得你正在努力理解 类型 因此,你的问题不容易理解。 typealias 其实没什么特别的,只是 别名 对于a 类型 。它不会给你任何额外的功能,只是一个更易读的代码。

    Swift没有Javascript那样的动态对象,你也不能直接从中重写功能。例如,Swift没有类似于 Object.values .

    --

    你的代码显然受到了Redux的启发,因此让我们看看一切在Redux中是如何工作的,以及如何将其转换为Swift。

    让我们从 Action .

    protocol Action {
       var type: String { get }
    }
    
    struct ActionImpl<PayloadType>: Action {
       let type: String
       let payload: PayloadType
    }
    

    这只是一个简单的想法,但它应该适用于大多数用例。请注意,在Redux中,动作基本上是一个可以包含以下内容的对象 任何东西 .我们可以用 payload: Any 在Swift中,但那将是丑陋的。

    现在,让我们定义状态。国家不是字典。状态是一种复杂的层次结构类型,例如:

    struct AppState1: Equatable {
        var value1: Int = 0 // default value
        var value2: String?
    }
    
    struct AppState2: Equatable {
        var value3: Double?
    }
    
    struct RootState: Equatable {
        var appState1 = AppState1()
        var appState2 = AppState2()
    }
    

    现在,在这种状态下,reducer函数应该具有以下类型:

    (AppState1, Action) -> AppState1
    (AppState2, Action) -> AppState2
    

    以及根部减速器:

    (RootState, Action) -> State
    

    正如你所看到的,它不是一个可以使用 类型别名 . 这在Javascript中更容易实现,因为Javascript在对象和字典之间以及字符串和键之间没有太大区别。而且Javascript中的所有函数都是同一类型的。。。 不过,在Swift中,我们可以用类似的方式组合类型安全的reducer:

    let appState1Reducer: (AppState1, Action) -> AppState1 = { state, action in
       switch action {
       case let action as ActionImpl<Int> where action.type == "changeValue1":
            var newState = state
            newState.value1 = action.payload
            return newState
       case let action as ActionImpl<String> where action.type == "changeValue2":
            var newState = state
            newState.value2 = action.payload
            return newState
       default:
          return state
       }
    }
    
    let appState2Reducer: (AppState2, Action) -> AppState2 = { state, action in
       switch action {
       case let action as ActionImpl<Double> where action.type == "changeValue3":
            var newState = state
            newState.value3 = action.payload
            return newState
       default:
          return state
       }
    }
    
    let rootReducer: (RootState, Action) -> RootState = { state, action in
        var newState = state
        newState.appState1 = appState1Reducer(state.appState1, action)
        newState.appState2 = appState2Reducer(state.appState2, action)
        return newState
    }
    
    let state = RootState()
    print(state)
    let action = ActionImpl(type: "changeValue2", payload: "New value!")
    let newState = rootReducer(state, action)
    print(newState)
    

    根减少器并不比 composeReducers Redux中的助手,它仍然是一个应该的函数。