假设我有一个班级class C<T>
。
我想编写一个函数f(_ a: Any) -> Bool
,当a
是继承自C
(或者是C
本身)的类的成员时,它返回true。我不关心专业化:传递C<Int>
,C<Double>
,C<Whatever>
都应该返回true
。
它似乎就像我应该只能写a is C
或a 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
答案 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应该如何使用的。 (你所要求的确实是不可能的,而且是有目的的。)写下这个协议,但不是空洞的黑客;填写你正在测试的内容,然后将其视为代码结构的一个漂亮部分!