使用 reduce() 在 Swift 中构建字典

Using reduce() to build a dictionary in Swift

我想使用函数式编程风格构建字典。我的 reduce() 似乎不起作用 - 我得到一个 "fatal error: unexpectedly found nil while unwrapping an Optional value"

func loadMoveToCalendarsRules(calendarIndex: Int) -> [String]? {
//    return something like ["phone call", "buzz", "ring"]
    return NSUserDefaults.standardUserDefaults().objectForKey(generateMoveToCalendarsRules_NSUserDefaultsKey(calendarIndex)) as? [String]
}

// Add indeces to an array of any type
func addIndices<T>(toArray: [T]) -> [(index: Int, value: T)] {
    return Array(zip(toArray.indices, toArray))
}

typealias CalendarRules = [EKCalendar : [String]]?
func buildCalendarRules(cals: [EKCalendar]) -> CalendarRules {
    let sortedCals = cals.sort { [=11=].title.lowercaseString < .title.lowercaseString }

    // build move to cal rules.
    let indexedCalList = addIndices(sortedCals)
    // go through the sorted calendars and build a dictionary that associates each calendar with a string array. (These are keywords that apply to the given calendar.)
    let calendarRules = indexedCalList.reduce(nil as CalendarRules) {
        accumulator, nextValue in
        var retVal: [EKCalendar : [String]]? = accumulator
        // if there are values found in NSUserDefaults for this calendar index then retrieve them.
        if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
            retVal![nextValue.value] = rulesForCurrentCal       // fatal error: unexpectedly found nil while unwrapping an Optional value
        }
        return retVal
    }

    print("------------ built calendar rules -------------")
    print(Array(arrayLiteral: calendarRules?.keys))
    print(Array(arrayLiteral: calendarRules?.values))

    return calendarRules
}

您的 retVal 是可选的,并且以 nil 开始(您传入的初始值),但您正在使用 retVal! 强制展开它。您可以只使用 [:] (一个空字典)作为初始值,然后 retVal 根本不需要是可选的。

您从 nil 开始,并且从未实例化 CalendarRules 字典,因此尝试使用 ! 对其执行强制解包的尝试将会失败。相反,测试它是否是 nil,如果是,则实例化一个。

在开始之前,我首先建议将日历规则定义为非可选类型。这样可以减少混乱:

typealias CalendarRules = [EKCalendar : [String]]

然后,您可以使用 nil-合并运算符 ??,在需要时实例化 CalendarRules 对象:

let calendarRules = indexedCalList.reduce(nil as CalendarRules?) { accumulator, nextValue in
    if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
        var retVal = accumulator ?? CalendarRules()
        retVal[nextValue.value] = rulesForCurrentCal
        return retVal
    }
    return accumulator
}

我觉得可能有更有效的方法,但这应该可以解决您的 "unexpectedly found nil" 错误。