【问题标题】:Swift 2.0 - generic factory function that returns a type determined by implementation of functionSwift 2.0 - 返回由函数实现确定的类型的通用工厂函数
【发布时间】:2015-08-18 02:56:33
【问题描述】:

这可能吗?

场景是,我希望一个函数接受一个与该函数的通用约束无关的参数,并返回依赖于所述参数的未知类型的结果。这些类型之间没有任何关系。一个可能是字符串,一个可能是 int,一个可能是字符串数组等。

我在协议中使用 typealias 对此进行了实验,每个符合它的对象都设置了自己的类型,并在其工作中使用类型别名。

我已经将此作为协议进行了实验:

protocol BaseFunctionality {
    typealias ReturnType
    var property: ReturnType { get set }
    func getData() -> ReturnType
}

然后我有几个符合要求的类:

class StringClass: BaseFunctionality {
    typealias ReturnType = String
    var property: ReturnType = "HELLO WORLD"
    func getData() -> ReturnType {
        return property
    }
}

class IntClass: BaseFunctionality {
    typealias ReturnType = Int
    var property: ReturnType = 12345
    func getData() -> ReturnType {
        return property
    }
}

所以,我想出的是这样的:

func getIt<T: BaseFunctionality>(int: Int) -> T.ReturnType {
    if (int == 0) {
        let stringClass = StringClass()
        return stringClass.getData() as! T.ReturnType // for some reason I have to as! this
    } else {
        let intClass = IntClass()
        return intClass.getData() as! T.ReturnType // same as above comment
    }
}

并这样称呼它:

let testing = getIt(1)

但是,我收到一条错误消息,

“无法使用类型为 '(int)' 的参数列表调用 'getIt'”。

我知道编译器在确定我到底想要什么作为返回类型时遇到问题,所以我想提供一个闭包,将T: BaseFunctionality 映射到它所拥有的属性。

func getIt<T:BaseFunctionality, U where U == T.ReturnType>(int:Int, unwrapType: T -> U ) -> U {
    if (int == 0) {
        let source = StringClass()
        return unwrapType(source as! T) // for some reason, source is not a valid T
    }
    else {
        let source = IntClass()
        return unwrapType(source as! T) // see above comment
    }
}

签名中U 的约束可能有问题,但我已经尝试了各种......

例如,我这样称呼它。

let data = getIt(1, mapToType: {(unwrapType) -> String in
    return unwrapType.property  as String
})

但是,这会导致操场上发生疯狂的事情......(崩溃)

有没有人知道如何在编译时使用未知的返回类型来实现这个神奇的功能?

这里是 swiftstub:http://swiftstub.com/800198020/?v=beta

谢谢!

【问题讨论】:

    标签: swift generics protocols factory swift2


    【解决方案1】:

    正如Qbyte所说或

    enum TextOrNum {
        case Text(s: String)
        case Num(x: Int)
    }
    
    func getIt(i: Int) -> TextOrNum {
        if i == 0 {
            return .Text("Hello")
        } else {
            return .Num(42)
        }
    }
    
    // usage
    switch getIt(0) {
    case let .Num(x):
        // use x return value as Int
    case let .Text(s):
        // use s return value as String
    }
    

    枚举的优点是编译器会检查你的所有情况。

    【讨论】:

      【解决方案2】:

      您只能使用Anyswitch 实现这种动态行为,该switch 将值强制转换为使用返回的类型作为类型化变量:

      // the function
      func getIt(i: Int) -> Any {
          if i == 0 {
              return "Hello"
          } else {
              return 42
          }
      }
      
      // usage
      switch getIt(0) {
      case let x as Int:
          // use the return value as Int
      case let str as String:
          // use the return value as String
      default: break
      }
      

      【讨论】:

      • 感谢@Qbyte!我最终采用了一种完全不同的方法来解决我的问题(这个例子是从领域中抽象出来的)
      猜你喜欢
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      • 2019-03-23
      • 1970-01-01
      相关资源
      最近更新 更多