在 Kotlin 中,“::class.simpleName”有什么作用?

Kun*_*ito 3 type-inference variable-assignment type-mismatch assignment-operator kotlin

val var1: Any = "Carmelo Anthony"

当我执行以下操作时,我的印象是::class.simpleName返回对象的变量类型:

val var1Type = var1::class.simpleName
print(var1Type)

我得到了String,但没有得到Any

但当我这样做时

val var2: String = var1

我得到一个Type mismatch: inferred type is Any but String was expected

Dai*_*Dai 6

  • 在 Kotlin 中,::class运算符有两种形式:
  • 在您的情况下,var1运行时类型为 ,String但静态类型为Any
    • 所以var1::class返回KClassfor String, not Any
  • 但与大多数静态类型语言一样,Kotlin 的类型系统不允许隐式缩小转换(即,给定一个类型为 的变量var2,您不能从另一个静态类型为 的变量 ( )String进行赋值,因为可能具有完全不兼容的运行时类型与,例如一个物体。 var2var3Anyvar3 StringInputStream
    • ...即使可以证明(通过手动执行程序) -Any类型的值将始终是String.
    • 然而幸运的是,Kotlin 的类型检查器是现代的,并且它的“智能转换”功能在使用运算符时遵循类型缩小的范围is,这很简洁(TypeScript 也有它,但我认为任何其他语言都没有) 。
      • 在无法使用智能强制转换或可以通过其他方式向自己证明向下强制转换是安全的情况下,请使用as运算符执行不安全强制转换。就像这样:var2: String = var1 as String
        • (有点令人困惑的是,其他语言用作安全as转换的运算符,啊)。

在上下文中

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)
}
Run Code Online (Sandbox Code Playgroud)

如果您熟悉其他语言,那么这里有一个不完整的等效操作及其语法表:

科特林 爪哇 JavaScript C# C++
获取静态类型 TypeName::class TypeName.class ConstructorName typeof(TypeName) typeid(TypeName)
获取运行时类型 variableName::class variableName.getClass() typeof variableName(内在)variableName.constructor(对象) variableName.GetType() typeid(variableName)
从名称(字符串)获取类型 Class.forName( typeName ).kotlin Class.forName( typeName ) eval( typeName )(永远不要这样做)
静态定义的运行时类型检查 variableName is TypeName variableName instanceof TypeName typeof variableName === 'typeName'(内在)或variableName instanceof ConstructorName(对象) variableName is TypeName
运行时动态类型检查 otherKClass.isInstance( variableName )或者otherKType.isSubtypeOf() otherClass.isAssignableFrom( variableName.getClass() ) otherType.IsAssignableFrom( variableName.GetType() )
不安全的缩小(又名沮丧) val n: NarrowType = widerVar as NarrowType; NarrowType n = (NarrowType)widerVar; variableName as TypeName(仅限 TypeScript) NarrowType n = (NarrowType)widerVar;
安全缩小(向下或null val n: NarrowType? = widerVar as? NarrowType; NarrowType n? = widerVar as NarrowType; dynamic_cast<NarrowType>( widerVar )
有条件缩小范围 variableName is TypeName func(x: unknown): x is TypeName保护函数(仅限 TypeScript) widerVar is TypeName n