Подтвердить что ты не робот

Что можно выразить в константе времени компиляции (const val)?

В документации для констант времени компиляции перечислены три требования, которые должно выполнить свойство, чтобы объявить его как 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()

Каковы точные правила для констант времени компиляции?

Есть ли список функций, которые я могу использовать в объявлении константы времени компиляции?

4b9b3361

Ответ 1

Точной документации по этому вопросу нет, но список функций, которые можно использовать в константных выражениях, можно найти в источниках компилятора здесь. Обратите внимание, что только те функции могут использоваться в константных выражениях, которые определены в пакете kotlin, в пользовательских перегруженных операторах компилятор сообщает об ошибках.

Ответ 2

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));

и opeartors оптимизированы для примитивных типов, поскольку у них нет методов в java, например:

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

код выше вашего 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] не может работать, потому что параметр indexed access operator является 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

Однако для операторов с фиксированными параметрами с Basic Type будет оптимизирован компилятор:

Обратите внимание, что эти операции, а также все остальные, оптимизированы для Основные типы и не вводят служебные вызовы функций для них.

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

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 поддерживают только примитивные типы и строки.