简体   繁体   English

如何在 Swift 中关联类型的协议闭包中使用 Void 类型

[英]how to use Void type in a closure of protocol with associatedtype in Swift

I've a little issue I cannot find an elegant way to use a closure with an associated type as a Void in a protocol.我有一个小问题,我找不到一种优雅的方法来使用具有关联类型的闭包作为协议中的 Void。

Let's say I've the following protocol:假设我有以下协议:

protocol MyProtocol {

  associatedtype OutputDataType
  associatedtype InputDataType

  var isCompleted: ( (InputDataType) -> OutputDataType)? { get set }
}

Now I've a class that conforms to this protocol with Void type inside the closure like this:现在我有一个符合这个协议的类,在闭包内有 Void 类型,如下所示:

class MyClass: MyProtocol {
  var isCompleted: ( () -> Void )? // Error: Type 'MyClass' does not conform to protocol 'MyProtocol'
}

So I tried this:所以我试过这个:

var isCompleted: ( (Void) -> Void )? // warning: When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?

And ended up with this "weird" syntax:并以这种“奇怪”的语法结束:

var isCompleted: ( (()) -> Void )?

or this verbose one:或者这个冗长的:

typealias InputDataType = Void
var isCompleted: ( (InputDataType) -> Void )?

But now when I want to assign this closure in an other class I need to explicitely use a "_" in parameter:但是现在当我想在另一个类中分配这个闭包时,我需要在参数中明确使用“_”:

myClass.isCompleted = { _ in
// other code
}

Isn't possible to use something like this:不可能使用这样的东西:

myClass.isCompleted = {
// other code
}

So do you know if it would be possible to get something more elegant like the example I quoted and expected?那么你知道是否有可能获得更优雅的东西,比如我引用和预期的例子?

Because you've declared isCompleted as necessary via the protocol, you will have to implement it in MyClass and unfortunately use the "weird" syntax.因为您已经通过协议根据需要声明了isCompleted ,所以您必须在MyClass实现它,不幸的是使用了“奇怪”的语法。

However, to make using it nicer, you can add an extension to the protocol for when InputDataType == Void that gives a convenience to accessing isCompleted without having to explicitly pass Void ... Something like this:但是,为了更好地使用它,您可以在InputDataType == Void时为协议添加一个扩展,这样可以方便地访问isCompleted而无需显式传递Void ......像这样的事情:

extension MyProtocol where InputDataType == Void {
    var isCompleted: (() -> OutputDataType)? {
        get {
            guard let isCompleted = self.isCompleted else { return nil }
            return { return isCompleted(()) }
        }
        set {
            if let newValue = newValue {
                self.isCompleted = { _ in return newValue() }
            } else {
                self.isCompleted = nil
            }
        }
    }
}

Then you can use the method on your class through the convenience, which gives you the last code example you were looking for:然后您可以通过方便的方式在您的类上使用该方法,这为您提供了您正在寻找的最后一个代码示例:

var myClass = MyClass()
myClass.isCompleted = {
    print("Hello World!")
}
myClass.isCompleted?()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM