2017-09-16 10 views
7

मैं स्विफ्ट में संदेश-आधारित आर्किटेक्चर के साथ प्रयोग कर रहा हूं। मैं उदाहरण के लिए एल्म आर्किटेक्चर के समान कुछ करने की कोशिश कर रहा हूं।संदेश-आधारित आर्किटेक्चर में सामान्य संदेश

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 [] 
     } 
    } 
} 

तो राज्य State द्वारा मॉडलिंग की है और आप Message रों भेजकर इसे बदल सकते हैं: यह कैसे मेरे कोड दिखता है। यदि गणना करने के लिए कोई दुष्प्रभाव हैं, तो उन्हें SideEffect संदेश के रूप में वापस कर दिया गया है और किसी और की देखभाल की जाएगी। साइड इफेक्ट समाप्त होने पर भेजने के लिए प्रत्येक SideEffect संदेश "कॉलबैक" तर्क लेता है, Message। यह बहुत अच्छा काम करता है।

अब, अगर मैं एक सामान्य साइड इफेक्ट संदेश चाहता हूं तो क्या होगा?

struct Request<ReturnType> { … } 

और अनुरोध लोड और प्रकार ReturnType का मान प्रदान करने के लिए एक संबंधित पक्ष प्रभाव है:: मैं कुछ इस तरह करना चाहते हैं

enum SideEffect<Message> { 
    case sendRequest(Request<T>, (T) -> Message) 
} 

लेकिन यह (जाहिर है) संकलन नहीं है , case को T से अधिक सामान्य होना होगा। मैं पूरे SideEffect सामान्य T से अधिक नहीं बना सकता, क्योंकि अन्य दुष्प्रभाव हैं जिनके पास T से कोई लेना देना नहीं है।

क्या मैं किसी भी तरह SideEffect संदेश Request<T> के साथ बना सकता हूं जो बाद में T के साथ Message प्रेषित करेगा? (मुझे लगता है कि मुझे this feature discussed on swift-evolution जैसे कुछ चाहिए।)

+0

कैसे के बारे में हम एक प्रोटोकॉल Returnable' बनाने के लिए और बनाने के 'ReturnType' इस प्रोटोकॉल के अनुरूप ? फिर हम इस प्रोटोकॉल के अनुरूप अन्य प्रकारों को भी 'स्ट्रिंग' जैसे विस्तारित कर सकते हैं। – sCha

+0

आप मिटाना 'टी' टाइप करना चाहते हैं, आमतौर पर इसे बंद करने के साथ किया जा सकता है (उदाहरण के लिए आप एक बंद कर देते हैं जो अनुरोध करता है और फिर परिणाम को आपके कार्य में पास करता है जो तब एक संदेश उत्पन्न करता है, इस प्रकार ' बाहरी दुनिया से टी ')। मैं एल्म आर्किटेक्चर से बिल्कुल परिचित नहीं हूं और इसलिए मुझे यकीन नहीं है कि आप 'अनुरोध' को कार्यान्वित करने की अपेक्षा कैसे कर रहे हैं, लेकिन [ऐसा कुछ] [http://swift.sandbox.bluemix.net/#/ प्रतिलिपि/59e15aad6cbea87f72c470cc) व्यवहार्य हो? – Hamish

+0

हामिश फिर से बचाव के लिए! मुझे लगता है कि यह वही है जो मुझे चाहिए था। मैं चारों ओर मिटाने के आसपास मार रहा था, लेकिन स्पष्ट रूप से मुझे अवधारणा के लिए काफी उपयोग नहीं किया गया था इसलिए मैं समाधान के साथ नहीं आया था। आपका बहुत बहुत धन्यवाद! मैंने आपकी टिप्पणी को उत्तर में परिवर्तित करने के लिए प्रश्न को ध्वजांकित किया है। – zoul

उत्तर

1

आप T मिटाएं टाइप करना चाहते हैं - आमतौर पर इसे बंद करने के साथ किया जा सकता है, क्योंकि वे उस संदर्भ को प्रकट किए बिना, जिस साइट पर बनाए गए हैं, संदर्भ से संदर्भित कर सकते हैं, बाहरी दुनिया में।

उदाहरण के लिए, एक नकली (एक async आपरेशन यह मानते हुए है) Request<T> साथ:

struct Request<T> { 

    var mock: T 

    func doRequest(_ completion: @escaping (T) -> Void) { 
     // ... 
     completion(mock) 
    } 
} 

हम एक RequestSideEffect<Message> है कि एक बंद है कि किसी भी (Message) -> Void कॉलबैक लेता रखती है, और उसके बाद निर्माण कर सकते हैं एक पर कब्जा कर लिया पर एक अनुरोध करता है

struct RequestSideEffect<Message> { 

    private let _doRequest: (@escaping (Message) -> Void) -> Void 

    init<T>(request: Request<T>, nextMessage: @escaping (T) -> Message) { 
     self._doRequest = { callback in 
      request.doRequest { 
       callback(nextMessage($0)) 
      } 
     } 
    } 

    func doRequest(_ completion: @escaping (Message) -> Void) { 
     _doRequest(completion) 
    } 
} 
012: Request<T> उदाहरण, एक (T) -> Message के माध्यम से परिणाम अग्रेषण, जिसके परिणामस्वरूप फिर वापस कॉलबैक करने के लिए (इस प्रकार प्रकार चर T रखने बंद में 'निहित') पारित किया जा सकता

अब आप अपने SideEffect<Message> इस तरह दिख सकता:

enum SideEffect<Message> { 
    case sendRequest(RequestSideEffect<Message>) 
} 

और तुम State इस तरह लागू कर सकते हैं:

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: 
      let sideEffect = RequestSideEffect(
       request: Request(mock: "foo"), nextMessage: Message.receiveResponse 
      ) 
      return [.sendRequest(sideEffect)] 
     case .receiveResponse(let response): 
      something = response 
      return [] 
     } 
    } 
} 

var s = State(something: "hello") 
let sideEffects = s.send(msg: .downloadSomething) 

for case .sendRequest(let sideEffect) in sideEffects { 
    sideEffect.doRequest { 
     _ = s.send(msg: $0) // no side effects expected 
     print(s) // State(something: "foo") 
    } 
} 
संबंधित मुद्दे