Swift Generic constraints in init

做~自己de王妃 提交于 2019-12-06 01:34:22

问题


I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:

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)
  }
}

You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?

Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.

Update

I'm using the following workaround: I create a top level function and removing the specialized init:

func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
  return left == right
}

Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)

It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.


回答1:


The problem is that the first init method

init<T: Equatable>(data: [T]) 

introduces a local type placeholder T which hides (and is completely unrelated to) the placeholder T of the Generic type, so it is essentially the same problem as in Array extension to remove object by value.

As of Swift 2 you can solve that with a "restricted extension":

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

For Swift 1.x the only solution is probably to define a global helper function

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

(and I could not think of a sensible name for the function :).



来源:https://stackoverflow.com/questions/31703790/swift-generic-constraints-in-init

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!