zou*_*oul 7 generics elm swift
我正在Swift中尝试基于消息的架构.我正在尝试做类似于Elm Architecture的事情.这是我的代码的样子:
enum SideEffect<Message> {
case sendRequest((String) -> Message)
}
protocol Component {
associatedtype Message
mutating func send(msg: Message) -> [SideEffect<Message>]
}
struct State: Component {
var something: String?
enum Message {
case downloadSomething
case receiveResponse(String)
}
mutating func send(msg: Message) -> [SideEffect<Message>] {
switch msg {
case .downloadSomething:
return [.sendRequest(Message.receiveResponse)]
case .receiveResponse(let response):
something = response
return []
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以状态是建模的State,你可以通过发送Messages 来改变它.如果有任何副作用要计算,它们将作为SideEffect消息返回,并由其他人处理.每条SideEffect消息都带有一个"回调"参数,a Message在副作用结束时发送.这非常有效.
现在,如果我想要一个通用的副作用消息怎么办?我想要这样的东西:
struct Request<ReturnType> { … }
Run Code Online (Sandbox Code Playgroud)
并且有相关的副作用来加载请求并返回类型的值ReturnType:
enum SideEffect<Message> {
case sendRequest(Request<T>, (T) -> Message)
}
Run Code Online (Sandbox Code Playgroud)
但是(显然)这不会编译,因为它case必须是通用的T.我不能完全SideEffect通用T,因为还有其他副作用与之无关T.
我能以某种方式创建SideEffect一个消息Request<T>以后将派遣Message有T?(我想我想要在swift-evolution上讨论这个功能.)
您需要输入擦除T\xe2\x80\x93,通常这可以通过闭包来完成,因为它们可以从创建它们的站点引用上下文,而不将该上下文暴露给外界。
例如,使用模拟Request<T>(假设它是异步操作):
struct Request<T> {\n\n var mock: T\n\n func doRequest(_ completion: @escaping (T) -> Void) {\n // ...\n completion(mock)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我们可以构建一个RequestSideEffect<Message>包含接受给定(Message) -> Void回调的闭包,然后对捕获的实例执行请求Request<T>,通过 a 转发结果(T) -> Message,然后可以将结果传递回回调(从而保持类型变量T\'包含在闭包中):
struct RequestSideEffect<Message> {\n\n private let _doRequest: (@escaping (Message) -> Void) -> Void\n\n init<T>(request: Request<T>, nextMessage: @escaping (T) -> Message) {\n self._doRequest = { callback in\n request.doRequest {\n callback(nextMessage($0))\n }\n }\n }\n\n func doRequest(_ completion: @escaping (Message) -> Void) {\n _doRequest(completion)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在你SideEffect<Message>可以看起来像这样:
enum SideEffect<Message> {\n case sendRequest(RequestSideEffect<Message>)\n}\nRun Code Online (Sandbox Code Playgroud)\n\n你可以State这样实现:
protocol Component {\n associatedtype Message\n mutating func send(msg: Message) -> [SideEffect<Message>]\n}\n\nstruct State: Component {\n\n var something: String\n\n enum Message {\n case downloadSomething\n case receiveResponse(String)\n }\n\n mutating func send(msg: Message) -> [SideEffect<Message>] {\n switch msg {\n case .downloadSomething:\n let sideEffect = RequestSideEffect(\n request: Request(mock: "foo"), nextMessage: Message.receiveResponse\n )\n return [.sendRequest(sideEffect)]\n case .receiveResponse(let response):\n something = response\n return []\n }\n }\n}\n\nvar s = State(something: "hello")\nlet sideEffects = s.send(msg: .downloadSomething)\n\nfor case .sendRequest(let sideEffect) in sideEffects {\n sideEffect.doRequest {\n _ = s.send(msg: $0) // no side effects expected\n print(s) // State(something: "foo")\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
232 次 |
| 最近记录: |