swift - 嵌套函数使 Swift 编译器崩溃

标签 swift generics nested mergesort nested-generics

我写了一个递归的 mergeSort 函数:

func mergeSort<T: Comparable>(inout array: [T]) {
    if array.count <= 1 {
        return
    }

    var leftSlice = [T](array[0..<array.count / 2])
    var rightSlice = [T](array[array.count / 2...array.endIndex - 1])

    mergeSort(&leftSlice)
    mergeSort(&rightSlice)
    array = merge(leftSlice, rightSlice)
}

func merge<T: Comparable>(var left: [T], var right: [T]) -> [T] {
    var mergedValues = [T]()

    while !left.isEmpty && !right.isEmpty {
        mergedValues.append(left.first! < right.first! ? left.removeAtIndex(0) : right.removeAtIndex(0))
    }

    if !left.isEmpty {
        mergedValues += left
    } else if !right.isEmpty {
        mergedValues += right
    }

    return mergedValues
}

现在,因为 merge() 只应该被 mergeSort() 使用,所以我把它放在了 mergeSort() 中,因此使 merge() 成为 nested function :

func mergeSort<T: Comparable>(inout array: [T]) {
    func merge<T: Comparable>(var left: [T], var right: [T]) -> [T] {
        var mergedValues = [T]()

        while !left.isEmpty && !right.isEmpty {
            mergedValues.append(left.first! < right.first! ? left.removeAtIndex(0) : right.removeAtIndex(0))
        }

        if !left.isEmpty {
            mergedValues += left
        } else if !right.isEmpty {
            mergedValues += right
        }

        return mergedValues
    }

    if array.count <= 1 {
        return
    }

    var leftSlice = [T](array[0..<array.count / 2])
    var rightSlice = [T](array[array.count / 2...array.endIndex - 1])

    mergeSort(&leftSlice)
    mergeSort(&rightSlice)
    array = merge(leftSlice, rightSlice)
}

现在 first版本工作正常,但 second一个没有。
怎么可能?

最佳答案

看起来您在编译器中发现了一个与嵌套泛型函数相关的错误。这是一个也会使 1.2 编译器崩溃的缩减:

func f<T>(t: T) {
    func g<U>(u: U) { }
}

但在这种情况下,您实际上不需要 merge 的通用版本。它的通用参数与外部函数相同,因此只需使用:

func mergeSort<T: Comparable>(inout array: [T]) {
    // no generic placeholder needed, T is the T for mergeSort
    func merge(var left: [T], var right: [T]) -> [T] {
      // etc.
    }
}

这似乎工作正常。

但是,还值得指出的是,在您的 merge 函数中,您在循环中调用 removeAtIndex,这是一个 O(n) 功能。这意味着您的归并排序不会具有预期的复杂性。

这里有一个可供考虑的替代版本:

func mergeSort<T: Comparable>(inout array: [T], range: Range<Int>? = nil) {

    func merge(left: Range<Int>, right: Range<Int>) -> [T] {    
        var tmp: [T] = []
        tmp.reserveCapacity(count(left) + count(right))

        var l = left.startIndex, r = right.startIndex

        while l != left.endIndex && r != right.endIndex {
            if array[l] < array[r] {
                tmp.append(array[l++])
            }
            else {
                tmp.append(array[r++])
            }
        }
        // where left or right may be empty, this is a no-op
        tmp += source[l..<left.endIndex]
        tmp += source[r..<right.endIndex]

        return tmp
    }

    // this allows the original caller to omit the range,
    // the default being the full array
    let r = range ?? indices(array)
    if count(r) > 1 {
        let mid = r.startIndex.advancedBy(r.startIndex.distanceTo(r.endIndex)/2)
        let left = r.startIndex..<mid
        let right = mid..<r.endIndex

        mergeSort(&array, range: left)
        mergeSort(&array, range: right)
        let merged = merge(left, right)
        array.replaceRange(r, with: merged)
    }
}

我还要说的是,由于 merge 本身可能是一个通用的有用函数,您不妨将其独立而不是嵌套(类似地,partition 实现快速排序时)。嵌套不会给你带来任何好处(除了我上面使用的从内部引用外部参数的技巧之外,无论如何这可能是一种不好的做法,我这样做主要是为了向你展示:)

关于swift - 嵌套函数使 Swift 编译器崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28679678/

相关文章:

java - 这个方法返回什么?

python - scikit learn 模型的嵌套并行性

excel - VBA:如何在循环中构建嵌套字典(ByVal?)

swift - skspritenode 显示白色图像

swift - 无尽的滚动背景

ios - 如何通过点击 swift 中的按钮来创建新 View (或 subview )?

c# - 通用对象比较 diff 例程

c# - c# 中的类(使用 filehelpers)- 可空字符串在其他可空类型不存在时给出错误

nested - DART 函数,嵌套/内部函数变量

ios - 为 UITableViewController 添加属性