Kotlin 编译时常量(const-val)可以表示什么?
编译时常量文档列出了属性需要满足的三个要求,以便将其声明为Kotlin 编译时常量(const-val)可以表示什么?,kotlin,Kotlin,编译时常量文档列出了属性需要满足的三个要求,以便将其声明为const val。这些是: 对象的顶层或成员 使用字符串类型或基元类型的值初始化 无自定义getter “无定制getter”要求使我相信我不能在常量声明中使用任何函数,但事实似乎并非如此。这些文件包括: const val bitmask = (5 shl 3) + 2 const val aComputedString = "Hello ${0x57.toChar()}orld${((1 shl 5) or 1).toChar(
const val
。这些是:
- 对象的顶层或成员
- 使用字符串类型或基元类型的值初始化
- 无自定义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()
编译时常量的确切规则是什么
编译时常量声明中是否有可以使用的函数列表?
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));
const val longValue = 1.toLong();
// java
static final long longValue = (long) 1 ;
const val third = "Hello world!"[3] //error
// will generate java code as
static final String third = "Hello world!".charAt(3) // error
const val third = "Hello".get(3) // ok
// ^
// when you calling the `get` function, you never using `operator` at all.
// it just a function invocation
comparedString
上面的代码可以工作,因为您使用的是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
运算符的多少个参数,因此会使用参数列表动态调用它,例如:
static final String aComputedString = "Hello " + ((char) 0x57)
+ "orld" + ((char) ((1 << 5) | 1));
const val longValue = 1.toLong();
// java
static final long longValue = (long) 1 ;
const val third = "Hello world!"[3] //error
// will generate java code as
static final String third = "Hello world!".charAt(3) // error
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.get(n)
可以工作,因为kotlin.String
是映射器类型,并且没有实现,因此编译器知道如何计算它,例如:
static final String aComputedString = "Hello " + ((char) 0x57)
+ "orld" + ((char) ((1 << 5) | 1));
const val longValue = 1.toLong();
// java
static final long longValue = (long) 1 ;
const val third = "Hello world!"[3] //error
// will generate java code as
static final String third = "Hello world!".charAt(3) // error
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()
无法分配给常量变量,因为它是一个扩展方法,并且有实现。kotlinconst val
只支持原语类型和字符串。没有关于这方面的确切文档,但是可以在常量表达式中使用的函数列表可以在编译器源代码中找到。请注意,只有那些函数可以在自定义重载运算符上的kotlin
包下定义的常量表达式中使用。编译器将报告错误。这是正确的,但它没有解释为什么我可以在const val
-声明中使用某些函数,很多函数都不是运算符函数。那么comparedInt
和comparedString
呢?“你好,世界!”[3]为什么不起作用?这似乎不是编译时常数的确切规则。@marstran您好,也许这就是您想要的。您提到的运算符重载页面告诉我,a[i]
被转换为a.get(i)
。我找不到任何东西表明它被翻译成了charAt
-method.Sure,但这仍然不能解释为什么a[I]
和a.get(I)
之间有区别,因为文档清楚地说第一个将被翻译成另一个。看起来像是一个编译器错误。那么这些函数除了在这个文件中之外没有一个共同的分母?