init中的Swift通用约束

Aar*_*man 6 generics init swift

我有泛型,我希望能够使用特定的约束来初始化它.约束仅用于初始化.班上的其他人都不在乎.这是一个简化的例子:

struct Generic<T> {
  let compare: (T, T) -> Bool
  init<T: Equatable>(data: [T]) {
    let handler: (T, T) -> Bool = { $0 == $1 }
    compare = handler
    insert(data)
  }

  init(compareHandler: (T, T) -> Bool, data[T]) {
    compare = self.compareHandler
    insert(data)
  }
}
Run Code Online (Sandbox Code Playgroud)

你可以看到有两个初始化器.第二个显然工作正常.但是,在第一个中,本地类型T与struct的泛型类型不匹配.因此,例如,尝试插入我得到的数据Cannot invoke 'insert' with an argument list of type '([T])'.我是否可以仅针对初始化或特定函数专门化Struct的泛型类型?

请注意,我已经尝试init<T where T:Equatable>(data: [T])过同样的效果.

更新

我正在使用以下解决方法:我创建一个顶级函数并删除专用的init:

func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
  return left == right
}
Run Code Online (Sandbox Code Playgroud)

struct的客户端可以使用以下命令初始化: Generic(compareHandler: equatableHandler, data: data)

它不是使用专业的"便利" init,但我认为它对我的目的来说足够好.我不是创建顶级函数的粉丝,但泛型经常用于"Equatable"泛型,因此我为客户端定义一次处理程序是有意义的.

Mar*_*n R 5

问题是第一个init方法

init<T: Equatable>(data: [T]) 
Run Code Online (Sandbox Code Playgroud)

引入了一个本地类型的占位符T,它隐藏(并且与TGeneric类型的占位符完全无关),因此它与Array扩展中的基本相同的问题是按值删除对象.

从Swift 2开始,你可以通过"限制扩展"来解决这个问题:

extension Generic where T : Equatable {
    init(data: [T]) {
        let handler: (T, T) -> Bool = { $0 == $1 }
        compare = handler
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

对于Swift 1.x,唯一的解决方案可能是定义全局辅助函数

func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
    return Generic(compareHandler:  { $0 == $1 }, data: data)
}
Run Code Online (Sandbox Code Playgroud)

(我无法想到这个功能的合理名称:).