Swift 当存储在可选变量中时,compactMap的行为不同

Swift 当存储在可选变量中时,compactMap的行为不同,swift,xcode,functional-programming,swift4.1,Swift,Xcode,Functional Programming,Swift4.1,考虑以下数组 let marks = ["86", "45", "thiry six", "76"] 我已经在以下两个案例中解释了我的怀疑 案例1 // Compact map without optionals let compactMapped: [Int] = marks.compactMap { Int($0) } print("\(compactMapped)") 结果-[86,45

考虑以下数组

let marks = ["86", "45", "thiry six", "76"]
我已经在以下两个案例中解释了我的怀疑

案例1

// Compact map without optionals
let compactMapped: [Int] = marks.compactMap { Int($0) }
print("\(compactMapped)")
结果-[86,45,76]

案例2

// Compact map with optionals
let compactMappedOptional: [Int?] = marks.compactMap { Int($0) }
print("\(compactMappedOptional)")
结果-[可选(86)、可选(45)、无、可选(76)]

为什么案例2的结果为“零”?有人能解释为什么在第二种情况下不是这样的[可选(86)、可选(45)、可选(76)]吗?(PFA游乐场)


我将此行为作为一个例子提交,结果它以“按预期工作”的形式返回。为了找到一种向您解释它的方法,我必须对响应进行一些思考;我认为这可以非常准确和清晰地表达它。我们走

要了解这里发生了什么,让我们自己编写类似于
compactMap
的东西。假设
compactMap
做了三件事:

  • 通过给定的变换映射原始数组,该变换预计将生成可选数组;在这个特定的示例中,它生成
    Int?
    元素

  • 过滤掉零

  • 强制打开选项(安全,因为现在没有零)

  • 下面是“正常”行为,分解为以下理解方式:

    let marks = ["86", "45", "thiry six", "76"]
    let result = marks.map { element -> Int? in
        return Int(element)
    }.filter { element in
        return element != nil
    }.map { element in
        return element!
    }
    
    好的,但在您的示例中,对
    [Int?]
    的转换告诉
    compactMap
    输出
    Int?
    ,这意味着它的第一个
    map
    必须生成
    Int???

    let result3 = marks.map { element -> Int?? in
        return Int(element) // wrapped in extra Optional!
    }.filter { element in
        return element != nil
    }.map { element in
        return element!
    }
    
    因此,第一个
    map
    生成双包装选项,即
    可选(可选(86))
    可选(可选(45))
    可选(无)
    可选(可选(76))

    所有这些都不是
    nil
    ,因此它们都会通过过滤器,然后都会展开一次,以给出打印出来的结果

    回答我报告的Swift专家承认,这有点违反直觉,但这是我们为自动行为付出的代价,在自动行为中,分配到可选的执行自动包装。换句话说,你可以说

    let i : Int? = 1
    
    因为
    1
    在您进入作业的过程中被包装在一个可选文件中。您的
    [Int?]
    演员阵容要求进行同样的行为

    解决方法是自己明确指定转换的输出类型:

    这会阻止编译器对map函数的输出类型得出自己的结论。问题解决了


    [您可能还想看看Swift中的on类型推断。]

    我没有在任何地方使用它。我只是想分析结果。好吧,那看起来像个bug。很容易描述发生了什么:在第二个示例中,我们实际上调用了
    map
    ,而不是
    compactMap
    。但我不知道为什么光是演员就会造成这种情况。我已经向bugs.swift.org提交了这个文件。他们都在幕后调用
    map
    。。。只有一个过滤掉了零,另一个没有,因为它不必..这是一个非常古老的行为;我刚刚在Xcode 9.2中确认了这一点。所以这可能是故意的。但我发现很难证明这一点;当然,它打破了一个人的及物性意识,在这种情况下,
    b=a;c=b
    给出了与
    c=a
    @KirilS不同的结果(
    c
    )。是的,我就是这么想的。它“看到”我们将要分配给一个
    [Int?]
    ,所以它对自己说,“哦,你毕竟愿意接受可选的,所以我没有工作要做。”但这仍然不是我所期望的语言的行为方式。好吧,这比我所期望的有趣得多!提供了解释和解决方法。
    let result3 = marks.compactMap {element -> Int? in Int(element) }