在 Kotlin 中,“::class.simpleName”是做什么的?
In Kotlin, what does "::class.simpleName" do?
val var1: Any = "Carmelo Anthony"
印象中::class.simpleName
returns对象的变量类型
当我执行以下操作时:
val var1Type = var1::class.simpleName
print(var1Type)
我得到 String
而不是 Any
但是当我这样做的时候
val var2: String = var1
我得到一个Type mismatch: inferred type is Any but String was expected
- 在 Kotlin 中,
::class
运算符有两种形式:
TypeName::class
- which returns a KClass
object for the static type TypeName
.
variableName::class
- variableName
的 which returns a KClass
object corresponding to the runtime type,并且 不是 variableName
的静态类型。 (Kotlin 在其文档中称其为“绑定类型”)。
- 在您的例子中,
var1
的运行时类型为 String
,但静态类型为 Any
。
- 所以
var1::class
returns String
的 KClass
,而不是 Any
。
- 但是 Kotlin 的类型系统,像大多数静态类型语言一样,不允许隐式缩小转换(即给定一个类型为
String
的变量 var2
,你不能 assign-to var2
来自另一个变量 (var3
) statically-typed 为 Any
,因为 var3
可能 具有与String
,例如 InputStream
对象。
- ...即使 也可以证明(通过遵循程序 by-hand)
Any
类型的值将始终是 String
.
- 然而,幸运的是,Kotlin 的 type-checker 是现代的 and its "Smart cast" feature follows the scope of type-narrowing 当使用
is
运算符时,这很整洁(TypeScript 也有,我认为任何其他语言都没有确实如此)。
- 在您不能使用 Smart-casts 或者可以用其他方式 证明 向下转型是安全的情况下,请使用
as
运算符来执行一个 unsafe cast。像这样:var2: String = var1 as String
。
- (有点令人困惑,其他语言使用
as
作为 safe 转换的运算符,argh)。
fun main() {
val var1: Any = "Carmelo Anthony"
val var1Type = var1::class.simpleName
println("var1's type: " + var1Type) // <-- This will print the *runtime type* of `var1` (String), not its static type (which is `Any`, *not* `String`).
/*
val var2: String = var1 // <-- Fails beause `var1` is `Any`, and `Any` is "wider" than `String`, and narrowing conversions always considered unsafe in languages like Kotlin, Java, etc.
*/
val var2Unsafe: String = var1 as String; // <-- Doing this is unsafe because it will throw if `var1` is not a String.
val var2Safe : String? = var1 as? String; // <-- Doing this is safe because it `var2Safe` will be null if `var1` is not a String.
println(var2Unsafe)
println(var2Safe)
}
如果您熟悉其他语言,那么这里有一个不完整的 table 等效操作及其语法:
Kotlin
Java
JavaScript
C#
C++
Get static type
TypeName::class
TypeName.class
ConstructorName
typeof(TypeName)
typeid(TypeName)
Get runtime type
variableName::class
variableName.getClass()
typeof variableName
(intrinsics) variableName.constructor
(objects)
variableName.GetType()
typeid(variableName)
Get type from name (string)
Class.forName( typeName ).kotlin
Class.forName( typeName )
eval( typeName )
(never do this)
Statically-defined runtime type check
variableName is TypeName
variableName instanceof TypeName
typeof variableName === 'typeName'
(intrinsics) or variableName instanceof ConstructorName
(objects)
variableName is TypeName
Runtime dynamic type check
otherKClass.isInstance( variableName )
or otherKType.isSubtypeOf()
otherClass.isAssignableFrom( variableName.getClass() )
otherType.IsAssignableFrom( variableName.GetType() )
Unsafe narrowing (aka downcast)
val n: NarrowType = widerVar as NarrowType;
NarrowType n = (NarrowType)widerVar;
variableName as TypeName
(TypeScript only)
NarrowType n = (NarrowType)widerVar;
Safe narrowing (downcast or null
)
val n: NarrowType? = widerVar as? NarrowType;
NarrowType n? = widerVar as NarrowType;
dynamic_cast<NarrowType>( widerVar )
Conditional narrowing in scope
variableName is TypeName
func(x: unknown): x is TypeName
guard functions (TypeScript only)
widerVar is TypeName n
val var1: Any = "Carmelo Anthony"
印象中::class.simpleName
returns对象的变量类型
当我执行以下操作时:
val var1Type = var1::class.simpleName
print(var1Type)
我得到 String
而不是 Any
但是当我这样做的时候
val var2: String = var1
我得到一个Type mismatch: inferred type is Any but String was expected
- 在 Kotlin 中,
::class
运算符有两种形式:TypeName::class
- which returns aKClass
object for the static typeTypeName
.variableName::class
-variableName
的 which returns aKClass
object corresponding to the runtime type,并且 不是variableName
的静态类型。 (Kotlin 在其文档中称其为“绑定类型”)。
- 在您的例子中,
var1
的运行时类型为String
,但静态类型为Any
。- 所以
var1::class
returnsString
的KClass
,而不是Any
。
- 所以
- 但是 Kotlin 的类型系统,像大多数静态类型语言一样,不允许隐式缩小转换(即给定一个类型为
String
的变量var2
,你不能 assign-tovar2
来自另一个变量 (var3
) statically-typed 为Any
,因为var3
可能 具有与String
,例如InputStream
对象。- ...即使 也可以证明(通过遵循程序 by-hand)
Any
类型的值将始终是String
. - 然而,幸运的是,Kotlin 的 type-checker 是现代的 and its "Smart cast" feature follows the scope of type-narrowing 当使用
is
运算符时,这很整洁(TypeScript 也有,我认为任何其他语言都没有确实如此)。- 在您不能使用 Smart-casts 或者可以用其他方式 证明 向下转型是安全的情况下,请使用
as
运算符来执行一个 unsafe cast。像这样:var2: String = var1 as String
。- (有点令人困惑,其他语言使用
as
作为 safe 转换的运算符,argh)。
- (有点令人困惑,其他语言使用
- 在您不能使用 Smart-casts 或者可以用其他方式 证明 向下转型是安全的情况下,请使用
- ...即使 也可以证明(通过遵循程序 by-hand)
fun main() {
val var1: Any = "Carmelo Anthony"
val var1Type = var1::class.simpleName
println("var1's type: " + var1Type) // <-- This will print the *runtime type* of `var1` (String), not its static type (which is `Any`, *not* `String`).
/*
val var2: String = var1 // <-- Fails beause `var1` is `Any`, and `Any` is "wider" than `String`, and narrowing conversions always considered unsafe in languages like Kotlin, Java, etc.
*/
val var2Unsafe: String = var1 as String; // <-- Doing this is unsafe because it will throw if `var1` is not a String.
val var2Safe : String? = var1 as? String; // <-- Doing this is safe because it `var2Safe` will be null if `var1` is not a String.
println(var2Unsafe)
println(var2Safe)
}
如果您熟悉其他语言,那么这里有一个不完整的 table 等效操作及其语法:
Kotlin | Java | JavaScript | C# | C++ | |
---|---|---|---|---|---|
Get static type | TypeName::class |
TypeName.class |
ConstructorName |
typeof(TypeName) |
typeid(TypeName) |
Get runtime type | variableName::class |
variableName.getClass() |
typeof variableName (intrinsics) variableName.constructor (objects) |
variableName.GetType() |
typeid(variableName) |
Get type from name (string) | Class.forName( typeName ).kotlin |
Class.forName( typeName ) |
eval( typeName ) (never do this) |
||
Statically-defined runtime type check | variableName is TypeName |
variableName instanceof TypeName |
typeof variableName === 'typeName' (intrinsics) or variableName instanceof ConstructorName (objects) |
variableName is TypeName |
|
Runtime dynamic type check | otherKClass.isInstance( variableName ) or otherKType.isSubtypeOf() |
otherClass.isAssignableFrom( variableName.getClass() ) |
otherType.IsAssignableFrom( variableName.GetType() ) |
||
Unsafe narrowing (aka downcast) | val n: NarrowType = widerVar as NarrowType; |
NarrowType n = (NarrowType)widerVar; |
variableName as TypeName (TypeScript only) |
NarrowType n = (NarrowType)widerVar; |
|
Safe narrowing (downcast or null ) |
val n: NarrowType? = widerVar as? NarrowType; |
NarrowType n? = widerVar as NarrowType; |
dynamic_cast<NarrowType>( widerVar ) |
||
Conditional narrowing in scope | variableName is TypeName |
func(x: unknown): x is TypeName guard functions (TypeScript only) |
widerVar is TypeName n |