【问题标题】:Unexpected Behavior in Swift Overloaded Function with Generic Parameters or T or Array of T带有泛型参数或 T 或 T 数组的 Swift 重载函数中的意外行为
【发布时间】:2017-10-25 19:34:12
【问题描述】:

我正在尝试通过泛型实现平面地图。 (是的,flatmap 已经是该语言的一部分。)我的尝试使用通用的重载函数来实现这一点。 (可能不是最有效的。我知道。我已经有了一个有效的命令式版本。)我发现出乎意料的是 flatten< T, U >( _ elem: T ) -> [ U ] 正在消耗调用 flatten 的数组,即使存在重载 func flatten< T, U >( _ ary: [ T ] ) -> [ U ] 也是如此。

我可以知道出了什么问题,但我似乎看不出原因,甚至看不出去哪里了解原因并可能修复它。

我什至尝试了一些演员表,只是为了看看,结果产生了错误,这对我来说很有意义。为什么要将T 转换为T[ T ] 转换为[ T ]?。还将ary 更改为elem,以查看这是否导致重载语义问题。产生相同的输出。

import Foundation

func flatten< T, U >( _ elem:    T   ) -> [ U ] {
    if let item = elem as? U {
        return [ item ]
    } else {
        return []
    }
}

func flatten< T, U >( _ ary:   [ T ] ) -> [ U ] {
    if ary.count == 0 {
        return []
    }

    return flatten( ary.first ) + flatten( Array( ary.dropFirst() ) )
}

let x: [ Int ] = flatten( [ 1, 2, [ 3, 4 ], [ [ 5, 6 ], nil, 7 ], 8, 9 ] )
print( x )  // Prints [1, 2, 8, 9 ] instead of [1, 2, 3, 4, 5, 6, 7, 8, 9]

【问题讨论】:

  • 比较stackoverflow.com/q/41980001/2976878——对flatten的递归调用的重载解决发生在flatten本身的实现中。从那个位置,编译器所知道的关于 ary.first 的所有信息就是它是某种类型的 T?;因此它不能分派到采用[T]flatten 的重载。
  • 如果您的问题被标记为重复,只需进行编辑并解释为什么它不是重复的(希望问题会重新打开)。此外,如果您的问题纯粹是转发,请不要转发。如果它们是相关的,则将它们链接起来,并在需要时解释它们是如何相关的。如果不是,那么最好不要在您的问题中讨论它们。
  • @Hamish,感谢您的回复和链接。那里有很多好东西。比我想象的还要棘手。
  • @Honey,谢谢。我会的,但问题实际上是重复的。无意的。这就是我提出这个问题的原因。我确实重新/搜索了我的答案,但是对于 Swift,它仍然非常……对我来说很不寻常。例如,对于模棱两可的下标,我会得到一个编译器错误,并且无法找出原因,因为真正的错误实际上是类型不匹配。然而,如果编译器说“无法转换 ArraySlice ...”,我什至不必发布我的(其他)问题。我刚刚修复了我的 n00b 错误。 :)。

标签: swift generics higher-order-functions


【解决方案1】:

编译器对使用从 ary.first 出来的封装可选选项感到困惑,这肯定会转到第一个函数签名。但即使修复了这个问题,仍然会在处理更简单的情况(例如 [[1,2][3,4]])时留下一些歧义。

解决这个问题的另一种方法是在内部处理所有类型,而不是将其留给编译器:

func flatten<U>( _ ary:[Any] ) -> [ U ]
{
    func makeFlat(_ flat:[U], _ elem:Any) -> [U]
    {
       if let item   = elem as? U     { return flat + [item] }
       if let ary    = elem as? [U]   { return flat + ary }
       if let subAry = elem as? [Any] { return flat + flatten(subAry) }
       return flat
    }
    return ary.reduce([U](),makeFlat)
}

【讨论】:

  • 谢谢。是的,我知道发生了什么事。 Hammish 链接的问题中提到的一些资源对这个主题很有启发性。我设法让其他几个版本的平面图工作。 (虽然不是你做的那样。很好!)我想尝试一个带有泛型的递归版本,并看看这里发生的所有学习。哈哈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-21
相关资源
最近更新 更多