在试图理解一个程序时,或者在某些极端情况下,找出某个东西的类型是很有用的。我知道调试器可以向您显示一些类型信息,在这些情况下,您通常可以依靠类型推断来避免不指定类型,但我仍然希望有类似Python的type()的东西。

dynamicType(参见这个问题)

更新:在Swift的最新版本中,obj已被更改。dynamicType现在提供了对类型的引用,而不是动态类型的实例。

这款似乎最有希望,但到目前为止我还没能找到实际的型号。

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self

我还尝试使用类引用来实例化一个新对象,这确实有效,但奇怪的是,给了我一个错误,说我必须添加一个必需的初始化器:

工作原理:

class MyClass {
    var count = 0
    required init() {
    }
}

let myClass2 = MyClass.self
let mc2 = MyClass2()

不过,要真正发现任何给定对象的类型,这仍然只是一小步

编辑:我已经删除了大量现在不相关的细节-如果你感兴趣,看看编辑历史:)


当前回答

如果你得到一个“总是真/失败”的警告,你可能需要在使用is之前强制转换为Any

(foo as Any) is SomeClass

其他回答

dynamicType。printClassName代码来自Swift书籍中的一个示例。我不知道如何直接获取自定义类名,但可以使用is关键字检查实例类型,如下所示。这个例子还展示了如何实现一个自定义的className函数,如果你真的想要类名作为字符串。

class Shape {
    class func className() -> String {
        return "Shape"
    }
}

class Square: Shape {
    override class func className() -> String {
        return "Square"
    }
}

class Circle: Shape {
    override class func className() -> String {
        return "Circle"
    }
}

func getShape() -> Shape {
    return Square() // hardcoded for example
}

let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true

注意:NSObject的子类已经实现了他们自己的className函数。如果您正在使用Cocoa,您可以使用这个属性。

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()

从Xcode 6.0.1开始(至少,不确定他们什么时候添加的),你原来的例子现在可以工作了:

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`

更新:

要回答最初的问题,您实际上可以成功地将Objective-C运行时与普通Swift对象一起使用。

试试下面的方法:

import Foundation
class MyClass { }
class SubClass: MyClass { }

let mc = MyClass()
let m2 = SubClass()

// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))

斯威夫特3:

if unknownType is MyClass {
   //unknownType is of class type MyClass
}

评论:我不明白@JérémyLapointe如何回答这个问题。使用type(of:)只能通过检查编译时信息来工作,即使实际类型是一个更特定的子类。现在在Swift 5.1中有一个更简单的方法来动态查询类型,而不需要像@Dash建议的那样诉诸dynamicType。有关我从哪里得到这些信息的更多详细信息,请参阅SE-0068:将Swift Self扩展到类成员和值类型。


Code

斯威夫特5.1

// Within an instance method context
Self.self

// Within a static method context
self

这允许使用Self作为引用包含类型(在结构、枚举和final类的情况下)或动态类型(在非final类的情况下)的简写。

解释

提案很好地解释了为什么这种方法改进了dynamicType:

Introducing Self addresses the following issues: dynamicType remains an exception to Swift's lowercased keywords rule. This change eliminates a special case that's out of step with Swift's new standards. Self is shorter and clearer in its intent. It mirrors self, which refers to the current instance. It provides an easier way to access static members. As type names grow large, readability suffers. MyExtremelyLargeTypeName.staticMember is unwieldy to type and read. Code using hardwired type names is less portable than code that automatically knows its type. Renaming a type means updating any TypeName references in code. Using self.dynamicType fights against Swift's goals of concision and clarity in that it is both noisy and esoteric. Note that self.dynamicType.classMember and TypeName.classMember may not be synonyms in class types with non-final members.

如果您只是需要检查变量是否属于X类型,或者它是否符合某种协议,那么您可以使用is或as?具体如下:

var unknownTypeVariable = …

if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}

这相当于Obj-C中的isKindOfClass。

这等价于conformsToProtocol或isMemberOfClass

var unknownTypeVariable = …

if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
    //unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
    //unknownTypeVariable is not of type <ClassName or ProtocolName>
}