# Переменные
В Ride вы можете объявить переменную только вместе с присвоением значения. Справа от знака =
должно находиться выражение. Значение переменной — результат вычисления этого выражения.
Значение переменной в дальнейшем недоступно для изменения.
Ride строго типизирован, а тип переменной определяется исходя из значения.
# Ленивые переменные
Ключевое слово let
используется для определения переменной с ленивой (отложенной) инициализацией: значение переменной вычисляется не сразу, а только при первом обращении к ней.
Примеры:
let a = 42 # Определение целочисленной переменной
let b = "Ride the Waves!" # Определение строковой переменной
Ленивую переменную можно определить глобально (в рамках скрипта), внутри любой функции или даже внутри определения переменной.
func lazyIsGood() = {
let c = {
let d = 1
true
}
c
}
Функция, определенная выше, возвращает значение true
, но переменная d
не будет инициализирована: значения неиспользуемых ленивых переменных не вычисляются.
Обратите внимание: значения ленивых переменных вычисляются не в том порядке, в котором они определены, а в порядке использования.
# не надо так
func foo() = {
...
let balanceBefore = wavesBalance(this).regular
let result = invoke(dApp2,"bar",args,[AttachedPayment(unit,100000000)])
let balanceAfter = wavesBalance(this).regular
if(balanceAfter < balanceBefore) then ... else...
}
В этом примере balanceAfter
вычисляется раньше, чем balanceBefore
, и их значения совпадают, а вызов функции invoke()
не происходит вовсе.
# Нетерпеливые переменные
Ключевое слово strict
используется для определения переменной с нетерпеливой инициализацией: значение нетерпеливой переменной вычисляется сразу, когда исполнение скрипта доходит до нее, то есть перед следующим выражением.
Определить нетерпеливую переменную можно только внутри другого определения, например, внутри тела функции. Значение нетерпеливой переменной не будет вычислено, если она определена внутри другого определения, которое не используется: например, внутри функции, которую не вызвали.
Применение нетерпеливой переменной для вызова dApp из dApp гарантирует порядок выполнения функций и применения действий скрипта. Пример:
func foo() = {
...
strict balanceBefore = wavesBalance(this).regular
strict result = invoke(dApp2,"bar",args,[AttachedPayment(unit,100000000)])
strict balanceAfter = wavesBalance(this).regular
if(balanceAfter < balanceBefore) then ... else...
}
В этом примере сначала вычисляется balanceBefore
, затем result
с вызовом функции invoke()
, затем balanceAfter
. Значения balanceBefore
и balanceAfter
могут отличаться, поскольку на балансе отражаются платежи в пользу dApp2
и действия, выполненные вызываемой функцией bar
.
Обратите внимание: совместное использование ленивых и нетерпеливых переменных может приводить к неожиданным эффектам. Пример:
# не надо так
{-# STDLIB_VERSION 8 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let lpTokenId = base58'...'
let rewardTokenId = base58'...'
@Callable(i)
func burn(amount: Int) = [ Burn(lpTokenId, amount) ]
@Callable(i)
func reward() = {
let p = value(i.payments[0])
if p.assetId != lpTokenId
then throw("Incorrect payment")
else {
let lpQty = assetInfo(lpTokenId).value().quantity
let rewardQty = assetInfo(rewardTokenId).value().quantity
let share = fraction(p.amount,rewardQty,lpQty)
strict result = invoke(this, "burn", [p.amount], [])
[
ScriptTransfer(i.caller, share, rewardTokenId)
]
}
}
Из-за использования ленивой переменной share
функция reward()
сначала вызывает функцию burn()
, а уже затем вычисляет share
. Например, если всего существует 100 токенов lpTokenId
и отправитель приложил к вызову скрипта 20 из них, то сначала сжигается 20 токенов, потом считается доля (20 токенов от оставшихся 80), и в результате отправитель получит не 20%, а 25% общего количества токена rewardTokenId
.
Нетерпеливые переменные добавлены в Стандартной библиотеке версии 5.
# Встроенные переменные
Стандартная библиотека содержит встроенные переменные, которые вы можете использовать в скриптах.