如何从通用函数返回值作为协议的实现?

时间:2016-08-09 22:13:04

标签: swift generics swift-protocols

我想为实现这些协议的对象构建协议映射。然后我希望能够获得给定协议的实现。

这是我到目前为止所得到的:

<iron-pages>

我可以这样称呼它:

class Services {
  var map = NSMapTable(keyOptions: .CopyIn, valueOptions: .WeakMemory)

  func register<T>(type: T, target: AnyObject) {
    map.setObject(target, forKey: String(type))
  }

  func get<T>(type: T) -> AnyObject {
    guard let target = map.objectForKey(String(type)) else {
      fatalError("Not registered")
    }
    return target
  }
}

这太棒了。但是当我想要检索它时:

protocol Foo {
  func qux()
}

class Bar: Foo {
  func qux() {}
} 

services.register(Foo.self, target: Bar())

...上面一行会产生错误:

  

Foo.swift:12:34:无法将调用结果类型'AnyObject'转换为预期类型'Foo'

如何指定泛型函数let foo: Foo = services.get(Foo.self) 返回实现get中引用的协议的对象?

我想避免不得不接听电话。

3 个答案:

答案 0 :(得分:1)

我不确定这是否符合你的目的,但你可以这样写:

class Services {
    var map = NSMapTable(keyOptions: .CopyIn, valueOptions: .WeakMemory)

    func register<T>(type: T.Type, target: T) {
        guard let object = target as? AnyObject else {
            fatalError("Cannot register")
        }
        map.setObject(object, forKey: String(type))
    }

    func get<T>(type: T.Type) -> T {
        guard let target = map.objectForKey(String(type)) as? T else {
            fatalError("Not registered")
        }
        return target
    }
}

答案 1 :(得分:0)

我知道你想避免贬低我,但我认为你应该使用:

if let foo: Foo = services.get(Foo.self) as? Foo {

}

因为在您的情况下,protocol Foo: class无效。

答案 2 :(得分:0)

如果让get返回泛型类型,你甚至不需要类型参数,因为你已经拥有它:

func get<T>() -> T {
    guard let target = map.objectForKey(String(T.self)) else {
        fatalError("Not registered")
    }
    return target as! T // or you could make the return type an Optional if you want to allow getting a service that wasn't registered.
}

然后你可以像这样使用它:

let foo: Foo = services.get()