如何测试对象是继承还是泛型类的成员?

时间:2017-06-04 04:09:21

标签: swift

假设我有一个班级class C<T>

我想编写一个函数f(_ a: Any) -> Bool,当a是继承自C(或者是C本身)的类的成员时,它返回true。我不关心专业化:传递C<Int>C<Double>C<Whatever>都应该返回true

似乎就像我应该只能写a is Ca as? C != nil作为该函数的主体一样,但是,这些都不能在游乐场中编译; swiftc抱怨说“通用参数'T'无法在转换为'C&lt; _&gt;'时推断出来”。如果我在f内写C作为实例方法,则C隐含C<T>,因此写let c = C<Int>(); c.f(C<Double>())会返回false

我可以通过编写P符合的协议C来解决这个问题,然后对其进行测试,但我认为这不是一个好的解决方案;这只是一个黑客。

有没有办法做到这一点?

以下是我为此尝试编写的所有代码:

class C<T> {
  func test(_ a: Any) -> (Bool, Bool) {
    return (type(of: a) == C.self, a is C)
  }
}

class D: C<Double> { }

let d = D()

func f(_ a: Any) -> Bool {
  return a is C // generic parameter 'T' could not be inferred in cast to 'C<_>'
}

d.test(C<Int>()) // false, false

// bad solution

protocol P { }

extension C: P { }

d is P // true

3 个答案:

答案 0 :(得分:0)

我不认为你有这样的语言特性,因为在不知道泛型类型参数的情况下,只知道对象是或C本身的子类是没有用的。

我的意思是,在知道之后你会做什么,是的,someObj确实属于C<Something>类型,而不是Something是什么?您无法对someObject执行任何操作。你不能投射它,所以你不能访问它的任何成员。

Swift的泛型非常非常严格,不像Java,它只是在运行时抛出泛型类型的窗口......

如果你坚持要这样做,你唯一的选择是使用你提到的黑客。

或者,如果你只是想检查a本身是否C,而不是它的任何子类,你可以使用它(只是为了好玩):

func f(a: Any) -> Bool {
    let regex = try! NSRegularExpression(pattern: "C<.+>")
    let typeString = String(describing: type(of: a))
    let range = NSRange(location: 0, length: typeString.characters.count)
    let matchRange = regex.rangeOfFirstMatch(in: typeString, range: range)
    return range.toRange() == matchRange.toRange()
}

答案 1 :(得分:0)

了解如何声明转储

func dump<T, TargetStream where TargetStream : TextOutputStream>(_ value: T, to target: inout TargetStream, name: String? = default, indent: Int = default, maxDepth: Int = default, maxItems: Int = default) -> T

并检查它产生的内容

class C<T>{}
class D:C<Double>{}

let c = C<Void>()
let d = D()

dump(c)
dump(d)

是的,dump是Swift标准库的一部分......它使用反射(对象镜像)来产生结果。

更新

我用一个文件main.swift

创建了名为 dumptest 的cli项目
//
//  main.swift
//  dumptest
//

class C<T>{}
class D:C<Double>{}
class E:D{}

let c = C<Void>()
let d = D()
let e = E()

var tc = ""
var td = ""
var te = ""

dump(c, to: &tc)
dump(d, to: &td)
dump(e, to: &te)

print("type info about c:", tc)
print("type info about d:", td)
print("type info about e:", te)

运行它报告的程序

type info about c: - dumptest.C<()> #0

type info about d: - dumptest.D #0
  - super: dumptest.C<Swift.Double>

type info about e: - dumptest.E #0
  - super: dumptest.D
    - super: dumptest.C<Swift.Double>

Program ended with exit code: 0

对于解析String变量,请检查stackoverflow,或者询问一个新问题......

让我们

import Cocoa

let v = NSView()
dump(v)

转储价值v我们有

- <NSView: 0x100a022a0> #0
  - super: NSResponder
    - super: NSObject
Program ended with exit code: 0

如果您需要某些东西&#34;更复杂&#34;,您可以玩 Mirror

答案 2 :(得分:0)

编写一个协议来指定你对这个测试的期望并不是一个黑客攻击。这正是Swift应该如何使用的。 (你所要求的确实是不可能的,而且是有目的的。)写下这个协议,但不是空洞的黑客;填写你正在测试的内容,然后将其视为代码结构的一个漂亮部分!