如何在Swift中确定变量的类型

38

Swift中是否有一种函数可以确定变量类型?我猜想可能会有类似Python中的type()的东西。

我希望有一种方法来判断Swift中变量是Foundation对象还是C变量,比如NSString vs String,或者NSArray vs array。这样我就可以在控制台中记录下来并清晰地看到它是什么了。

例如,我想知道下面第一个array的推断类型是什么:

var array = [1,2,3]  // by default NSArray or array?
var array:[Int] = [1,2,3]
var array:NSArray = [1,2,3]
var array:Array<Any> = [1,2,3]

我已经看过如何判断一个给定的变量是否属于给定的类型的答案,这在这个问题中有介绍,但我想问的与此相当不同。


不是我知道的,但你可以自己编写一个。 - Ali Gajani
我已经编辑了问题,以使我的陈述更加清晰。 - piaChai
你能给出一个你想要使用这些知识的代码示例吗?如果类型在编译时已知,你可能可以使用一个通用函数,类似于 func show<T>(x:T) { println("\(x) is of type \(T)" }。如果在编译时不知道类型,我不确定是否可能,因为似乎 C 值没有必要的运行时元数据。(可惜我无法尝试,因为苹果仍未批准我的开发者帐户。) - Jeremy
1
我不同意将这个问题关闭为如何在Swift中获取对象的类型的重复。尽管按照书面表述,这个问题可能是一个合适的重复,但事实上,所有的答案,包括被接受的答案,都只涉及确定一个值是否属于给定类型。除非那个提问者想要取消接受那个答案,否则我认为他们应该将问题缩小到检查一个值是否属于给定类型,使其与这个问题有所区别。 - Jeremy
我同意,“确定给定类型”和“直接确定类型”是不同的。 - piaChai
我已编辑此问题以消除与 https://dev59.com/7WAf5IYBdhLWcg3w9mts 的歧义,并投票重新开放。它们都是有用的、类似的问题,但答案却非常不同,因此将它们分开会很有用。 - Jeremy
5个回答

26

您可以通过使用.dynamicType属性来获取值的类型对象的引用。这相当于Python中的type()函数,并在Swift文档中提到了语言参考:类型:元类型类型

var intArray = [1, 2, 3]
let typeOfArray = intArray.dynamicType

使用这个类型对象,我们可以创建一个相同数组类型的新实例。
var newArray = typeOfArray()
newArray.append(5)
newArray.append(6)
println(newArray)

[5, 6]

我们可以看到,通过尝试追加一个浮点数,这个新的值的类型仍然相同([Int]):

newArray.append(1.5)

error: type 'Int' does not conform to protocol 'FloatLiteralConvertible'

如果我们导入Cocoa并使用混合类型的数组字面量,我们可以看到创建了一个NSArray
import Cocoa

var mixedArray = [1, "2"]
let mixedArrayType = mixedArray.dynamicType

var newArray = mixedArrayType()
var mutableArray = newArray.mutableCopy() as NSMutableArray

mutableArray.addObject(1)
mutableArray.addObject(1.5)
mutableArray.addObject("2")

println(mutableArray)

(1, "1.5", 2)

然而,目前似乎没有一种通用的方法可以生成类型对象的字符串描述,因此它可能无法起到你所要求的调试作用。

NSObject派生的类型确实有一个.description()方法,正如在SiLo的答案中使用的那样

println(mixedArrayType.description())

__NSArrayI

然而,这种操作在 Swift 内置的数组等类型中并不存在。
println(typeOfArray.description())

error: '[Int].Type' does not have a member named 'description'

顺便提一下:你可以始终使用 String(obj) 代替 obj.description()(如果可用,它将使用描述)。 - Tali
6
.dynamicType现在已经被弃用。相应的typeof等价语现在是type(of: myvariable)。 - xiay
@logicor 感谢提供的信息。您想对此帖子提出修改建议(这样您就可以获得修订的功劳)吗?如果不行,我稍后会自己进行编辑。 - Jeremy

24

选中想要检查的变量,然后按住option键并单击它。

在此输入图片描述


不回答这个问题,但它回答了我来这里的问题。 - undefined

10

虽然这是可能的,但并不一定容易也不一定有用:

func getClassName(obj : AnyObject) -> String
{
    let objectClass : AnyClass! = object_getClass(obj)
    let className = objectClass.description()

    return className
}

let swiftArray = [1, 2, 3]
let swiftDictionary = ["Name": "John Doe"]
let cocoaArray : NSArray = [10, 20, 30]
var mutableCocoaArray = NSMutableArray()

println(getClassName(swiftArray))
println(getClassName(swiftDictionary))
println(getClassName(cocoaArray))
println(getClassName(mutableCocoaArray))

输出:

_TtCSs22ContiguousArrayStorage00007F88D052EF58
__NSDictionaryM
__NSArrayI
__NSArrayM

在Swift中,使用isas关键字更好。许多基础类使用类群(如您可以看到的__NSArrayI(不可变)和__NSArrayM(可变)。

请注意有趣的行为。 swiftArray默认使用Swift Array<Int>,而swiftDictionary默认为NSMutableDictionary。有了这种行为,我真的不会依赖于任何确定的类型(首先检查)。


2
为什么不直接使用object_getClassName呢? - Brian

9

上面有人提到过,但我认为这应该作为答案而不是评论出现。现在你可以简单地使用type(of: ___):

var red, green, blue: Double
print(type(of: green))

收益率

双倍


0

我在调试时使用断点,但如果您需要在运行时检查它们是否与某种类型匹配,则 drewag 是正确的。

另一件事是使用断言测试数据类型,这只适用于调试,但使用断言可以设置条件,如果满足则应用程序崩溃。

也许像这样:assert(let tArray == oldArray as? NSArray[] //如果不是NSArray,则应用程序崩溃)


这个检查程序用于检查变量是否为特定类型,而不是它的具体类型。感谢您的输入。 - user5306470

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接