什么可以在编译时常量(const val)中表达?

编译时常量的文档列出了属性需要履行的三个要求,以便将其声明为const val 。 这些是:

  • 对象的顶级或成员
  • 使用String类型的值或基元类型初始化
  • 没有自定义的getter

“无自定义getter”的要求使我相信我不能在常量声明中使用任何函数,但是这似乎并非如此。 这些编译:

 const val bitmask = (5 shl 3) + 2 const val aComputedString = "Hello ${0x57.toChar()}orld${((1 shl 5) or 1).toChar()}" const val comparedInt = 5.compareTo(6) const val comparedString = "Hello".compareTo("World!") const val toStringedInt = 5.compareTo(6).toString() const val charFromString = "Hello World!".get(3) 

但是,这些不会编译:

 // An extension function on Int. const val coercedInt = 3.coerceIn(1..5) // Using operator syntax to call the get-function. const val charFromString = "Hello World!"[3] // An immediate type is not a primitive. const val stringFromImmediateList = "Hello World!".toList().toString() // Using a function defined by yourself. fun foo() = "Hello world!" const val stringFromFunction = foo() 

编译时常量的确切规则是什么?

有一个我可以在编译时常量声明中使用的函数列表?

这里没有确切的文档,但是在常量表达式中可以使用的函数列表可以在这里的编译器资源中找到 。 请注意,只有那些函数可以在kotlin包下定义的常量表达式中使用,在定制的重载操作符上编译器会报告错误。

getter不是方法调用,确实是属性声明的一部分,例如下面的代码不能被编译。

 const val charFromString get() = "foo" // ^--- const using getter can't be compiled 

aComputedString常量使用字符串模板,就像java中的字符串连接一样,例如:

 static final String aComputedString = "Hello " + ((char) 0x57) + "orld" + ((char) ((1 << 5) | 1)); 

并且操作符针对基本类型进行了优化,因为它们在java中没有方法,例如:

 const val longValue = 1.toLong(); // java static final long longValue = (long) 1 ; 

comparedString你的kotlin.String上面的代码可以工作的是,你正在使用kotlin.String而不是java.lang.String ,对于映射类型kotlin.String也进行了优化,因为在kotlin没有实现,如果你直接尝试java.lang.String您可以获得预期的编译器错误:

 typealias JavaString = java.lang.String; // v--- error const val comparedString = JavaString("Hello").compareTo("World!") 

"Hello world!"[3]不能工作,因为索引访问操作符的参数类型是vararg参数,所以编译器不能优化它,因为它不知道将接收到多少个get操作符的参数,所以它是动态调用List <KtExpression>列表,而不是,例如:

 const val third = "Hello world!"[3] //error // will generate java code as static final String third = "Hello world!".charAt(3) // error 

但是,对于具有基本类型的固定参数的操作员,将由编译器进行优化:

请注意,这些操作以及所有其他操作都针对 基本类型进行了优化 ,并且不会为它们引入函数调用的开销。

 const val comparison = "Hello" > "World";// ok 

kotlin.String String.get(n)可以工作,因为kotlin.String是一个映射器类型,它没有实现,因此编译器知道如何计算它,例如:

  const val third = "Hello".get(3) // ok // ^ // when you calling the `get` function, you never using `operator` at all. // it just a function invocation 

String.toList()不能分配给一个常量变量,因为它是一个扩展方法并有实现。 而kotlin const val只支持原始类型 s和字符串 s。