Swift中的递归块

XCo*_*ool 4 recursion swift

我一直在尝试将这段代码从Objective-C(取自https://gist.github.com/mikeash/1254684)转换为Swift.我已经成功地使用它来根据API调用的结果重复一段代码.在Swift中有更好的方法吗?

dispatch_block_t recursiveBlockVehicle(void (^block)(dispatch_block_t recurse)) {
    return ^{
        block(recursiveBlockVehicle(block));
    };
}
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏.

Air*_*ity 6

这是你的obj-c版本的直接翻译:

func recursiveBlockVehicle(block: @escaping (()->Void)->Void) -> ()->Void {
    return { block(recursiveBlockVehicle(block: block)) }
}

// test usage
var i = 5
let block = recursiveBlockVehicle { recurse in
    if i > 0 {
        print("\(i--) ")
        recurse()
    }
    else {
        println("blastoff!")
    }
}

block()  // prints 5 4 3 2 1 blastoff!
Run Code Online (Sandbox Code Playgroud)

(我已经提到了,dispatch_block_t因为它在Swift版本中没有必要,但你可以使用它而()->Void不是代替你喜欢)

对于1参数版本,您可以使用泛型而不是obj-c id方法,因此它可以创建类型安全的单参数递归块:

func recursiveBlockVehicle<T>(block: @escaping (T, (T)->Void)->Void) -> (T)->Void {
    return { param in block(param, recursiveBlockVehicle(block: block)) }
}

let block1: (Int)->Void = recursiveBlockVehicle { i, recurse in
    if i > 0 {
        print("\(i) ")
        recurse(i-1)
    }
    else {
        print("blastoff!")
    }
}


block1(5)  // prints 5 4 3 2 1 blastoff!
Run Code Online (Sandbox Code Playgroud)

(和Swift重载意味着你不必给它们不同的名字)

...如果你想让你的递归函数返回一个值:

func recursiveBlockVehicle<T,U>(block: @escaping (T, (T)->U)->U) -> (T)->U {
    return { (param: T)->U in block(param, recursiveBlockVehicle(block: block)) }
}

let factorial: (Int)->Int = recursiveBlockVehicle { i, factorial in
    return i > 1 ? i*factorial(i-1) : 1
}

factorial(4)  // returns 24
Run Code Online (Sandbox Code Playgroud)

请注意,这最后一个是你真正需要的只有一个-因为TU可以Void,它所服务的目的,零参数无返回一个太,但你必须写封锁采取两个参数(其中第一个你可以忽略,因为它将是无效的,即:

let block: ()->() = recursiveBlockVehicle { _, recurse in
Run Code Online (Sandbox Code Playgroud)

如果您喜欢这种东西,您应该查看2014 WWDC Advanced Swift视频,它是一个记忆递归函数调用者的例子.