【问题标题】:Swift check type against a generic type针对泛型类型快速检查类型
【发布时间】:2018-01-10 16:03:46
【问题描述】:

我有一个带有 1 个参数的泛型函数,并想用泛型类型检查传递的参数的类型。像这样的:

func generic<T>(parameter: AnyObject) -> Bool {
    if parameter is T {
        return true
    } else {
        return false
    }
}

但是我不知道怎么称呼这个

generic<String>("Hello")

给我一​​个编译器错误:“无法显式特化泛型函数 通用(“你好”)

【问题讨论】:

    标签: swift


    【解决方案1】:

    你不能告诉函数它的泛型占位符的类型是什么(与泛型结构不同)。它必须从上下文中推断出它们,例如它的论点。

    一种方法是添加另一个与类型T 相关的参数。您可以使用所需类型的元类型,而不是传入一个虚拟值:

    func generic<T>(parameter: AnyObject, type: T.Type) -> Bool {
        if parameter is T {
            return true
        } else {
            return false
        }
    }
    
    let o: AnyObject = "hello"
    generic(o, String.self)    // true
    generic(o, NSString.self)  // also true
    generic(o, Int.self)       // false
    

    但是,我想问你,你认为你在这里取得了什么成就?您基本上只是将is 实现为一个函数:

    o is String     // true
    o is NSString   // true
    o is Int        // false
    

    泛型的重点是对参数进行泛型操作,但您并没有给函数任何特定类型的参数来实际执行任何工作(因此无法推断)。

    【讨论】:

    • 我有一个更复杂的场景。我只是简化了我遇到的问题。
    • 我认为您已将其简化到很明显做您正在做的事情没有意义的地步。
    • ^ 我需要在通用函数中正确访问动态类型名称 T.self 以获得正确的实体名称(核心数据),而不是抽象实体名称(不存在),其中 。这种方法对我有用
    【解决方案2】:

    检查泛型是否是哪个类。

    protocol Some {}
    class SomeClass: Some {}
    class AClass: Some {}
    func test(_ t: T) -> String {
        if T.self == SomeClass.self {
            return "Some Class"
        } else {
            return "Another Class"
        }
    }
    
    print(test(SomeClass())) // Some Class
    print(test(AClass())) // Another Class
    

    【讨论】:

      【解决方案3】:

      这种情况不适合泛型。您只是要求针对一种类型测试一个对象。如果这总是一个 AnyObject,你可以尝试这样的事情:

      func istest(parameter: AnyObject, whattype: AnyObject.Type) -> Bool {
          if parameter.dynamicType === whattype.self {
              return true
          } else {
              return false
          }
      }
      

      如果你真的想要一个可以特化的泛型,你不能明确地特化一个函数,所以你必须将你的函数包装在一个泛型类型中并对其进行特化:

      struct Generic<T> {
          func generic(parameter: AnyObject) -> Bool {
              if parameter is T {
                  return true
              } else {
                  return false
              }
          }
      }
      
      let ok = Generic<String>().generic("howdy")
      let ok2 = Generic<Int>().generic(1)
      

      但正如我已经说过的那样,您给出的示例并不是这样做的好人选。请记住,泛型是在编译时解析的——我们已经知道解析的类型将是什么。因此,您的测试毫无意义,因为您已经知道答案。这就是为什么我向您展示了一个替代函数,其中值和类型都是未知的。

      【讨论】:

      • AnyObject.Type 可以写成AnyClasswhattype.selfwhattype 相同。而parameter.dynamicType === whattype 测试对象的类是否正是给定的类,这与is 的含义不同。原意可以parameter.isKindOfClass(whattype).
      • @newacct 我说“类似”。我知道is 给出的结果与=== 不同,但我不想直接涉及 Cocoa Foundation 方法。这只是一个“服务建议”。
      【解决方案4】:

      更通用的方法:

      struct Asserter<T>{
          func generic(_ val:Any) -> Bool{
              let type = type(of: val)
              return T.self == type
          }
      }
      _ = Asserter<String>().generic(2)//false
      _ = Asserter<String>().generic("")//true
      

      【讨论】:

        猜你喜欢
        • 2016-12-01
        • 1970-01-01
        • 2013-09-14
        • 1970-01-01
        • 2016-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-18
        相关资源
        最近更新 更多