编译时常量的文档列出了属性需要满足的三个要求,以便将其声明为 const val
. 这些是:
-
顶级或对象的成员
-
使用String类型或基本类型初始化
-
没有自定义的吸气剂
“没有自定义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()
编译时常量的确切规则是什么?
是否有我可以在编译时常量声明中使用的函数列表?
2 回答
没有关于此的确切文档,但可以在编译器源here中找到可以在常量表达式中使用的函数列表 . 请注意,只有那些函数可以在
kotlin
包下定义的常量表达式中使用,在自定义重载运算符编译器将报告错误 .getter
不是方法调用,实际上,它是's a part of property declaration, for example, the code below can' t被编译 .aComputedString
常量使用字符串模板,就像java中的字符串连接一样,例如:和opeartor针对原始类型进行了优化,因为它们在java中没有方法,例如:
你的
comparedString
上面的代码可以工作的是你正在使用kotlin.String
而不是java.lang.String
,因为映射类型kotlin.String
也是优化的,因为在kotlin中没有实现,如果你直接尝试java.lang.String
,你可以获得预期的编译器错误:"Hello world!"[3]
无法正常工作,因为indexed access operator的参数类型是vararg
,因此编译器可以知道get
运算符将接收多少个参数,因此使用List<KtExpression>列表动态调用它,例如:但是,对于具有基本类型的固定参数的运算符,将由编译器进行优化:
String.get(n)
可以工作,因为kotlin.String
是一个映射器类型,它没有实现,因此编译器知道如何计算它,例如:String.toList()
无法分配给常量变量,因为它是一个扩展方法并且具有实现 . 和kotlinconst val
只支持原始类型和字符串 .