在Swift的闭包中本地维护状态

时间:2014-10-13 15:51:18

标签: swift closures

是否有任何方法可以在闭包内声明变量并使其在枚举调用之间保持其状态。具体来说,我想在一个数组上写一个.filter闭包,它返回一个没有重复的数组版本。像这样的东西。

let withDupes = ["C", "D", "A", "J", "J", "D", "M", "Z", "A"]  

let noDupes = withDupes.filter {  
    static var seenLetters: [Character] = [ ]  //would like to use static like in C  
    if !contains(seenLetters, $0) {  
        seenLetters.append($0)  
                return true  
            }  
            else {  
                return false  
            }  
    }  

// noDupes理想情况下现在是[" C"," D"," A"," J",&#34 ; M"," Z"]

当我尝试以这种方式使用静态时,Swift报告错误,如果我全局声明了seeLetters,.filter工作正常。是否有我遗漏或滥用的语言功能?

1 个答案:

答案 0 :(得分:1)

正如您所发现的,Swift不允许您直接在函数或闭包中定义static变量。但是,还有另一种方法可以完成你想要做的事情。如果您将重复数据删除代码移至其自己的函数中,则可以创建一个范围为该函数的seenLetters Array,并在filter调用中使用该函数。像这样:

let withDupes = ["C", "D", "A", "J", "J", "D", "M", "Z", "A"]

func deduplicate(arr: [String]) -> [String] {
    var seenLetters = [String]()
    return arr.filter {
        if !contains(seenLetters, $0) {
            seenLetters.append($0)
            return true
        }
        else {
            return false
        }
    }
}

let noDupes = deduplicate(withDupes)

请注意,由于您可以在其他函数中嵌入函数,因此可以正常工作:

func someFunction() {
    let withDupes = ["C", "D", "A", "J", "J", "D", "M", "Z", "A"]

    func deduplicate(arr: [String]) -> [String] {
        /* ... */
    }

    let noDupes = deduplicate(withDupes)
}

如果您因某些原因想要创建一个单独的函数来执行此操作,那么您实际上也可以使用闭包来完成此操作。诀窍是将闭包包装在另一个闭包中,该闭包定义一个本地seenLetters变量并返回原始闭包。这样,seenLetters的作用域是外部闭包,你的内部闭包可以按照你的意图使用它。

let noDupes = withDupes.filter({
    var seenLetters = [String]()
    return {
        if !contains(seenLetters, $0) {
            seenLetters.append($0)
            return true
        }
        else {
            return false
        }
    }
}()) // Immediately calling the outer closure so that the inner one is returned to filter

需要注意的一些事项......首先,您需要将外部闭包的返回值传递给filter函数,您只需立即调用它即可。第二,你不能将它用作尾随闭包,因此你必须在()的{​​{1}}调用中将其包含在filter中。三,这与使用嵌入式功能基本相同,它只是一种更紧凑的形式。