Julia Language
@goto и @label
Поиск…
Синтаксис
- @goto label
- метка @label
замечания
Чрезмерное использование или неправильное использование расширенного потока управления делает код трудным для чтения. @goto
или его эквиваленты на других языках при неправильном использовании приводит к нечитаемому коду спагетти.
Подобно языкам типа C, нельзя переключаться между функциями в Julia. Это также означает, что @goto
невозможно на верхнем уровне; он будет работать только внутри функции. Кроме того, нельзя переходить от внутренней функции к ее внешней функции или от внешней функции к внутренней функции.
Проверка ввода
Хотя это не традиционно считается циклом, макросы @goto
и @label
могут использоваться для более продвинутого потока управления. Один случай использования - когда отказ одной части должен привести к повторению целой функции, часто полезной при проверке ввода:
function getsequence()
local a, b
@label start
print("Input an integer: ")
try
a = parse(Int, readline())
catch
println("Sorry, that's not an integer.")
@goto start
end
print("Input a decimal: ")
try
b = parse(Float64, readline())
catch
println("Sorry, that doesn't look numeric.")
@goto start
end
a, b
end
Однако этот вариант использования часто более понятен с помощью рекурсии:
function getsequence()
local a, b
print("Input an integer: ")
try
a = parse(Int, readline())
catch
println("Sorry, that's not an integer.")
return getsequence()
end
print("Input a decimal: ")
try
b = parse(Float64, readline())
catch
println("Sorry, that doesn't look numeric.")
return getsequence()
end
a, b
end
Хотя оба примера делают то же самое, второе легче понять. Однако первый из них более эффективен (поскольку он позволяет избежать рекурсивного вызова). В большинстве случаев стоимость звонка не имеет значения; но в ограниченных ситуациях первая форма приемлема.
Очистка ошибок
В таких языках, как C, оператор @goto
часто используется, чтобы гарантировать, что функция очищает необходимые ресурсы, даже в случае ошибки. Это менее важно в Julia, потому что вместо этого часто используются блоки исключений и try
finally
.
Однако код Julia может взаимодействовать с C-кодом и API-интерфейсом C, поэтому иногда функции должны быть написаны как C-код. Приведенный ниже пример надуман, но демонстрирует общий прецедент. Код Julia вызовет Libc.malloc
для выделения некоторой памяти (это имитирует вызов API C). Если не все распределения успешны, то функция должна освобождать ресурсы, полученные до сих пор; в противном случае возвращается выделенная память.
using Base.Libc
function allocate_some_memory()
mem1 = malloc(100)
mem1 == C_NULL && @goto fail
mem2 = malloc(200)
mem2 == C_NULL && @goto fail
mem3 = malloc(300)
mem3 == C_NULL && @goto fail
return mem1, mem2, mem3
@label fail
free(mem1)
free(mem2)
free(mem3)
end