【问题标题】:Swift Array.insert genericsSwift Array.insert 泛型
【发布时间】:2014-09-02 19:02:01
【问题描述】:
func getIndex<T: Equatable>(valueToFind: T) -> Int? {...}

mutating func replaceObjectWithObject<T: Equatable>(obj1: T, obj2: T) {
    if let index = self.getIndex(obj1) {
        self.removeAtIndex(index)
        self.insert(obj2, atIndex: index)           // Error here: 'T' is not convertible to 'T'
    }
}

我有一个假设用另一个元素替换一个元素的功能。但我对Generics 不是很熟悉,也不知道为什么这不起作用。请帮忙。

如果我从 mutating func 中删除 Equatable,则错误消息会跳转到该 func 的第一行,然后如果我将其替换为 func find(),则会出现与第 3 行相同的错误。

【问题讨论】:

  • 你能提供insert方法的实现,或者至少是它的签名吗?
  • nvm...我知道了 - 这是一个 Array 扩展,不是吗?
  • 有点相切,但该错误消息令人困惑,因为Array 使用 T 作为其通用子类型。这是说T(此函数的泛型类型)不能转换为T(数组的泛型类型)。如果将方法签名更改为 U 而不是 T 会更清晰。

标签: arrays generics swift


【解决方案1】:

这实际上是不可能的通过扩展在现有的 Swift 协议和泛型系统下 - 你不能为一个类型的泛型子类型添加额外的约束,所以你不能扩展Array 的方法要求其内容符合Equatable

您可以通过内置的 Array 类型看到这个限制——没有myArray.find(element) 方法,但是一个全局函数find() 接受一个集合和一个元素,具有集合元素为Equatable的通用约束:

func find<C : CollectionType where C.Generator.Element : Equatable>(domain: C, value: C.Generator.Element) -> C.Index?

可以为您的方法执行此操作 - 您只需要编写一个类似的顶级函数:

func replaceObjectWithObject<C : RangeReplaceableCollectionType where C.Generator.Element : Equatable>(inout collection: C, obj1: C.Generator.Element, obj2: C.Generator.Element) {
    if let index = find(collection, obj1) {
        removeAtIndex(&collection, index)
        insert(&collection, obj2, atIndex: index)
    }
}

var myArray = [1, 2, 3, 4, 5]
replaceObjectWithObject(&myArray, 2, 7)
// 1, 2, 7, 4, 5

【讨论】:

  • 使用未声明类型 RangeReplaceableCollectionType,'Generator' 不是'C'类型的成员
  • 您使用的是哪个测试版? RangeReplaceableCollectionType 进入 beta 6。
  • 呵呵...我正在使用 beta 4
  • 感谢您的解释。我希望我们能找到一种方法来在 Swift 中的成员方法上添加额外的类型约束(例如,就像在 Scala 中一样)。在单个表达式中混合顶级函数和成员函数调用会使其更难阅读(也更难编写)。
【解决方案2】:

您是如何声明您的Array 分机的?问题是您的泛型函数需要Equatable 类型的参数,但是当您声明数组时,您指定了Equatable 类的特定实现,例如StringT 不是没有演员表的 String

【讨论】:

    【解决方案3】:

    使用类/结构函数无法完成您尝试做的事情 - @Nate Cook 使用全局函数提供了一个非常好的解决方案。

    顺便说一句,如果在您的扩展方法中将T 替换为V,那么它不起作用的原因会变得更清楚:它们是不同的类型。这也解释了为什么如果从 Equatable 中删除依赖项会出现相同的错误:该数组包含 T 类型的对象,但您试图插入 V 值。

    【讨论】:

      【解决方案4】:

      这个答案是针对她所说的一个重复问题:Create swift array extension for typed arrays

      有一种方法可以解决仅适用于特定类型数组的 Array 扩展。但是您必须使用带有 Any 类型元素的 Array,这在某种程度上绕过了 Swift 的类型系统。但是即使数组中有其他类型的元素,代码仍然有效。请参见下面的示例。

      class Job {
          var name: String
          var id: Int
          var completed: Bool
      
          init(name: String, id: Int, completed: Bool) {
              self.name = name
              self.id = id
              self.completed = completed
          }
      }
      
      var jobs: [Any] = [
          Job(name: "Carpenter", id: 32, completed: true),
          Job(name: "Engineer", id: 123, completed: false),
          Job(name: "Pilot", id: 332, completed: true)]
      
      
      
      extension Array {
      
          // These methods are intended for arrays that contain instances of Job
      
          func withId(id: Int) -> Job? {
              for j in self {
                  if  (j as? Job)?.id == id {
                      return j as? Job
                  }
              }
              return nil
          }
      
          func thatAreCompleted() -> [Job] {
              let completedJobs =  self.filter { ($0 as? Job) != nil && ($0 as? Job)!.completed}
              return completedJobs.map { $0 as! Job }
          }
      }
      
      jobs.withId(332)
      println(jobs.withId(332)?.name)
      //prints "Optional("Pilot")"
      
      let completedJobs = jobs.thatAreCompleted().map {$0.name}
      println(completedJobs)
      //prints "[Carpenter, Pilot]"
      

      【讨论】:

        【解决方案5】:

        您可以使用带有 where 子句约束的扩展,我使用的是 Xcode 7.3.1

        extension Array where Element: Equatable {
            func testEqutability() {
                let e1 = self[0]
                let e2 = self[1]
                if e1 == e2 {//now we can use == to test Element equtability
                    //do something 
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多