Close protocol implementation in Swift

I would like to create some functions in my Swift project that can accept either an object or a closure that returns this type of object. Of course, I could define the same function with multiple signatures in each place, but this is verbose. I would also like to be able to create types of safe lists of these objects / objects-returns-closures, but I cannot do this without some general type describing both things.

This is what I would like to do.

typealias StringClosure = () -> String

protocol Stringable {
    func toStringClosure() -> StringClosure
}

extension String : Stringable {
    func toStringClosure() -> StringClosure {
        return { return self }
    }
}

extension StringClosure : Stringable {
    func toStringClosure() -> StringClosure {
        return self
    }
}

func printStringable(a : Stringable) {
    print(a.toStringClosure()())
}


var stringableList : Stringable[] = ["cat", {return "dog"}, "gecko"]

for stringable in StringableList {
    printStringable(stringable)
}

But this does not work, because I cannot actually expand my type StringClosurefor implementation Stringable. I could make a stringableListlist of types Any, but not a safe type.

Listing Solution

, , , , , . :

enum StringableEnum {
    case Str(String)
    case Fun(StringClosure)
}

func printStringableEnum(a : StringableEnum) {
    switch (a) {
    case let .Str(value):
        print(value)
    case let .Fun(value):
        print(value())
    }
}

var enumList : StringableEnum[] = [.Str("cat"), .Fun({return "dog"}), .Str("gecko")]

for element in enumList {
    printStringableEnum(element)
}

, , API , , printStringableEnum, .Str .Fun. API!

, , - ?

+4
3

, . Strings, . :

let myString = "Hello"
printStringable({return  myString})

, :

func f<T>(value : T) -> () -> T  {
    return {return value}
}

printStringable(f("Hello"))
printStringable(f(myString))

, , .

Edit

:

enum StringableEnum {
    case Str(String)
    case Fun(() -> String)

    init(_ string : String) {
        self = .Str(string)
    }

    init(_ closure : () -> String) {
        self = .Fun(closure)
    }

    var value : String {
        switch(self) {
            case let .Str(value):
                return value
            case let .Fun(closure):
                return closure()
        }
    }
}

, , :

var stringable = StringableEnum("Hello")
stringable = StringableEnum({return "Hello"})

,

stringable.value
+2

: . Beta 4, , Apple , 1.0 Swift.


@auto_closure , , , , @auto_closure.

- Swift __conversion StringClosures, :

typealias StringClosure = () -> String

extension String {
    func __conversion() -> StringClosure {
        return { self } // 'return' can be omitted inside a single-expression closure
    }
}

// type inferencing automatically figures out that
// stringableList should be [StringClosure] and applies
// the conversion method to promote the string entries into
// self-returning closures
var stringableList = ["cat", { println("side-effects are bad"); return "dog"}, "gecko"]

func printStringClosure(s: StringClosure) {
    println(s())
}

for s in stringableList {
    printStringClosure(s)
}

printStringClosure("test")
printStringClosure { let a = 5*5; return "\(a)" }
+2

Do not forget that swift has the ability to create lazily calculated variables like this (they are not limited to classes / structures):

var lazy : String {
    return "Hello"
}

printStringable(lazy)

This is a simpler solution for your lazy calculations / closures that have problems with side effects if you don't need parameterized closures.

0
source

Source: https://habr.com/ru/post/1547204/


All Articles