Control Flow

Julia, çeşitli kontrol akışı yapıları sunar:

İlk beş kontrol akışı mekanizması, yüksek seviyeli programlama dilleri için standarttır. Task standart değildir: geçici olarak askıya alınmış hesaplamalar arasında geçiş yapmayı mümkün kılarak yerel olmayan kontrol akışı sağlar. Bu güçlü bir yapıdır: hem istisna işleme hem de işbirlikçi çoklu görev, Julia'da görevler kullanılarak uygulanır. Günlük programlama, görevlerin doğrudan kullanımını gerektirmez, ancak belirli problemler görevler kullanılarak çok daha kolay bir şekilde çözülebilir.

Compound Expressions

Bazen, birkaç alt ifadenin sırasıyla değerlendirildiği ve son alt ifadenin değerini döndüren tek bir ifadeye sahip olmak kullanışlıdır. Bunu başarmak için iki Julia yapısı vardır: begin blokları ve ; zincirleri. Her iki bileşik ifade yapısının değeri son alt ifadenin değeridir. İşte bir begin bloğuna bir örnek:

julia> z = begin
           x = 1
           y = 2
           x + y
       end
3

Bu ifadeler oldukça küçük ve basit olduğundan, kolayca tek bir satıra yerleştirilebilirler; işte bu noktada ; zincirleme sözdizimi işe yarar:

julia> z = (x = 1; y = 2; x + y)
3

Bu sözdizimi, Functions ile tanıtılan kısa tek satırlık fonksiyon tanım biçimi ile özellikle kullanışlıdır. Tipik olmasına rağmen, begin bloklarının çok satırlı olması veya ; zincirlerinin tek satırlı olması gerekmez:

julia> begin x = 1; y = 2; x + y end
3

julia> (x = 1;
        y = 2;
        x + y)
3

Conditional Evaluation

Koşullu değerlendirme, bir boolean ifadesinin değerine bağlı olarak kodun belirli bölümlerinin değerlendirilmesine veya değerlendirilmemesine olanak tanır. İşte if-elseif-else koşullu sözdiziminin anatomisi:

if x < y
    println("x is less than y")
elseif x > y
    println("x is greater than y")
else
    println("x is equal to y")
end

Eğer koşul ifadesi x < y doğru ise, o zaman ilgili blok değerlendirilir; aksi takdirde koşul ifadesi x > y değerlendirilir ve eğer bu doğru ise, ilgili blok değerlendirilir; eğer her iki ifade de doğru değilse, else bloğu değerlendirilir. İşte burada uygulamada:

julia> function test(x, y)
           if x < y
               println("x is less than y")
           elseif x > y
               println("x is greater than y")
           else
               println("x is equal to y")
           end
       end
test (generic function with 1 method)

julia> test(1, 2)
x is less than y

julia> test(2, 1)
x is greater than y

julia> test(1, 1)
x is equal to y

elseif ve else blokları isteğe bağlıdır ve istenildiği kadar elseif bloğu kullanılabilir. if-elseif-else yapısındaki koşul ifadeleri, ilk true değerini döndüren ifade bulunana kadar değerlendirilir; bu noktadan sonra ilişkili blok değerlendirilir ve daha fazla koşul ifadesi veya blok değerlendirilmez.

if blokları "sızdıran" yani yerel bir kapsam tanımlamaz. Bu, if koşulları içinde tanımlanan yeni değişkenlerin if bloğundan sonra da kullanılabileceği anlamına gelir, hatta daha önce tanımlanmamış olsalar bile. Bu nedenle, yukarıdaki test fonksiyonunu şu şekilde tanımlayabilirdik:

julia> function test(x,y)
           if x < y
               relation = "less than"
           elseif x == y
               relation = "equal to"
           else
               relation = "greater than"
           end
           println("x is ", relation, " y.")
       end
test (generic function with 1 method)

julia> test(2, 1)
x is greater than y.

Değişken relation, if bloğu içinde tanımlanmıştır, ancak dışarıda kullanılmaktadır. Ancak, bu davranışa bağlı olarak, tüm olası kod yollarının değişken için bir değer tanımladığından emin olun. Yukarıdaki işlevdeki aşağıdaki değişiklik, bir çalışma zamanı hatasına yol açar.

julia> function test(x,y)
           if x < y
               relation = "less than"
           elseif x == y
               relation = "equal to"
           end
           println("x is ", relation, " y.")
       end
test (generic function with 1 method)

julia> test(1,2)
x is less than y.

julia> test(2,1)
ERROR: UndefVarError: `relation` not defined in local scope
Stacktrace:
 [1] test(::Int64, ::Int64) at ./none:7

if blokları aynı zamanda bir değer döndürür, bu da birçok diğer dilden gelen kullanıcılar için sezgisel olmayabilir. Bu değer, seçilen dalda yürütülen son ifadenin döndürdüğü değerdir, bu nedenle

julia> x = 3
3

julia> if x > 0
           "positive!"
       else
           "negative..."
       end
"positive!"

Kısa koşullu ifadelerin (tek satırlık) genellikle Julia'da Kısa Devre Değerlendirmesi kullanılarak ifade edildiğini unutmayın; bu, bir sonraki bölümde açıklanmıştır.

C, MATLAB, Perl, Python ve Ruby'den farklı olarak - ancak Java ve birkaç diğer daha katı, tipli diller gibi - bir koşullu ifadenin değeri true veya false dışında bir şey olduğunda bir hata oluşur:

julia> if 1
           println("true")
       end
ERROR: TypeError: non-boolean (Int64) used in boolean context

Bu hata, koşulun yanlış türde olduğunu gösterir: Int64 yerine gereken Bool.

Sözde "üçlü operatör", ?:, if-elseif-else sözdizimi ile yakından ilişkilidir, ancak daha uzun kod bloklarının koşullu yürütülmesi yerine tek ifade değerleri arasında koşullu bir seçim gerektiğinde kullanılır. Üç operand alan tek operatör olduğu için bu ismi alır:

a ? b : c

a ifadesi, ? öncesinde bir koşul ifadesidir ve üçlü işlem, koşul a true ise : öncesindeki b ifadesini, false ise : sonrasındaki c ifadesini değerlendirir. ? ve : etrafındaki boşlukların zorunlu olduğunu unutmayın: a?b:c gibi bir ifade geçerli bir üçlü ifade değildir (ancak ? ve : sonrasında bir satır sonu kabul edilebilir).

Bu davranışı anlamanın en kolay yolu bir örneğe bakmaktır. Önceki örnekte, println çağrısı üç dal tarafından paylaşılmaktadır: tek gerçek seçim, hangi sabit dizeyi yazdırmaktır. Bu, üçlü operatör kullanılarak daha öz bir şekilde yazılabilir. Açıklık adına, önce iki yönlü bir versiyonunu deneyelim:

julia> x = 1; y = 2;

julia> println(x < y ? "less than" : "not less than")
less than

julia> x = 1; y = 0;

julia> println(x < y ? "less than" : "not less than")
not less than

Eğer x < y ifadesi doğruysa, tüm üçlü operatör ifadesi "less than" stringine değer verir, aksi takdirde "not less than" stringine değer verir. Orijinal üçlü örnek, üçlü operatörün birden fazla kullanımını bir araya getirmeyi gerektirir:

julia> test(x, y) = println(x < y ? "x is less than y"    :
                            x > y ? "x is greater than y" : "x is equal to y")
test (generic function with 1 method)

julia> test(1, 2)
x is less than y

julia> test(2, 1)
x is greater than y

julia> test(1, 1)
x is equal to y

Zincirleme işlemleri kolaylaştırmak için, operatör sağdan sola doğru ilişkilendirilir.

Önemli olan, if-elseif-else gibi, : öncesindeki ve sonrasındaki ifadelerin yalnızca koşul ifadesi true veya false olarak değerlendirildiğinde sırasıyla değerlendirildiğidir:

julia> v(x) = (println(x); x)
v (generic function with 1 method)

julia> 1 < 2 ? v("yes") : v("no")
yes
"yes"

julia> 1 > 2 ? v("yes") : v("no")
no
"no"

Short-Circuit Evaluation

&& ve || operatörleri Julia'da mantıksal "ve" ve "veya" işlemlerine karşılık gelir ve genellikle bu amaçla kullanılır. Ancak, ek bir kısa devre değerlendirme özelliğine sahiptirler: ikinci argümanlarını mutlaka değerlendirmezler, aşağıda açıklandığı gibi. (Kısa devre davranışı olmadan mantıksal "ve" ve "veya" olarak kullanılabilen bit düzeyinde & ve | operatörleri de vardır, ancak & ve |'nin değerlendirme sırası için && ve ||'dan daha yüksek önceliğe sahip olduğunu unutmayın.)

Kısa devre değerlendirmesi, koşullu değerlendirmeye oldukça benzer. Bu davranış, && ve || boolean operatörlerine sahip olan çoğu imperatif programlama dilinde bulunur: bu operatörlerle bağlı bir dizi boolean ifadesinde, tüm zincirin nihai boolean değerini belirlemek için gerekli olan minimum sayıda ifade değerlendirilir. Bazı diller (Python gibi) bunları and (&&) ve or (||) olarak adlandırır. Açıkça, bu şu anlama gelir:

  • a && b ifadesinde, b alt ifadesi yalnızca a ifadesi true olarak değerlendirildiğinde değerlendirilir.
  • a || b ifadesinde, b alt ifadesi yalnızca a ifadesi false olarak değerlendiğinde değerlendirilir.

Mantık, a && b ifadesinin a yanlışsa false olması gerektiğidir, b'nin değeri ne olursa olsun, ve benzer şekilde, a || b ifadesinin a doğruysa true olması gerektiğidir, b'nin değeri ne olursa olsun. Hem && hem de || sağa doğru bağlanır, ancak &&'nin önceliği ||'den daha yüksektir. Bu davranışı denemek kolaydır:

julia> t(x) = (println(x); true)
t (generic function with 1 method)

julia> f(x) = (println(x); false)
f (generic function with 1 method)

julia> t(1) && t(2)
1
2
true

julia> t(1) && f(2)
1
2
false

julia> f(1) && t(2)
1
false

julia> f(1) && f(2)
1
false

julia> t(1) || t(2)
1
true

julia> t(1) || f(2)
1
true

julia> f(1) || t(2)
1
2
true

julia> f(1) || f(2)
1
2
false

&& ve || operatörlerinin çeşitli kombinasyonlarının birleşim sırası ve önceliği ile aynı şekilde kolayca deney yapabilirsiniz.

Bu davranış, Julia'da çok kısa if ifadelerine alternatif oluşturmak için sıklıkla kullanılır. if <cond> <statement> end yerine, <cond> && <statement> yazılabilir (bu, <cond> ve sonra <statement> olarak okunabilir). Benzer şekilde, if ! <cond> <statement> end yerine, <cond> || <statement> yazılabilir (bu, <cond> ya da <statement> olarak okunabilir).

Örneğin, bir özyinelemeli faktöriyel rutini şu şekilde tanımlanabilir:

julia> function fact(n::Int)
           n >= 0 || error("n must be non-negative")
           n == 0 && return 1
           n * fact(n-1)
       end
fact (generic function with 1 method)

julia> fact(5)
120

julia> fact(0)
1

julia> fact(-1)
ERROR: n must be non-negative
Stacktrace:
 [1] error at ./error.jl:33 [inlined]
 [2] fact(::Int64) at ./none:2
 [3] top-level scope

Boolean işlemleri kısa devre değerlendirmesi olmadan, Mathematical Operations and Elementary Functions'da tanıtılan bit düzeyindeki boolean operatörleri ile yapılabilir: & ve |. Bunlar normal fonksiyonlardır, infiks operatör sözdizimini desteklerler, ancak her zaman argümanlarını değerlendirirler:

julia> f(1) & t(2)
1
2
false

julia> t(1) | t(2)
1
2
true

if, elseif veya üçlü operatörde kullanılan koşul ifadeleri gibi, && veya || operatörlerinin operandları boolean değerler (true veya false) olmalıdır. Koşullu bir zincirde son giriş dışında herhangi bir yerde boolean olmayan bir değer kullanmak bir hatadır:

julia> 1 && true
ERROR: TypeError: non-boolean (Int64) used in boolean context

Diğer yandan, bir koşul zincirinin sonunda her türlü ifade kullanılabilir. Bu ifade, önceki koşullara bağlı olarak değerlendirilecek ve döndürülecektir:

julia> true && (x = (1, 2, 3))
(1, 2, 3)

julia> false && (x = (1, 2, 3))
false

Repeated Evaluation: Loops

İfadelerin tekrar değerlendirilmesi için iki yapı vardır: while döngüsü ve for döngüsü. İşte bir while döngüsü örneği:

julia> i = 1;

julia> while i <= 3
           println(i)
           global i += 1
       end
1
2
3

while döngüsü koşul ifadesini (i <= 3 bu durumda) değerlendirir ve bu ifade true olduğu sürece while döngüsünün gövdesini de değerlendirmeye devam eder. Eğer koşul ifadesi while döngüsüne ilk ulaşıldığında false ise, gövde asla değerlendirilmez.

for döngüsü, yaygın tekrar eden değerlendirme kalıplarını yazmayı kolaylaştırır. Yukarıdaki while döngüsü gibi yukarı ve aşağı saymak çok yaygın olduğundan, daha özlü bir şekilde for döngüsü ile ifade edilebilir:

julia> for i = 1:3
           println(i)
       end
1
2
3

Burada 1:3, 1, 2, 3 sayı dizisini temsil eden bir range nesnesidir. for döngüsü bu değerler üzerinde yineleyerek her birini sırayla i değişkenine atar. Genel olarak, for yapısı 1:3 veya 1:3:13 gibi herhangi bir "iterable" nesne (veya "kapsayıcı") üzerinde döngü oluşturabilir (her 3. tam sayıyı gösteren bir StepRange, 1, 4, 7, …, 13) veya diziler gibi daha genel kapsayıcılara, iterators defined by user code veya harici paketler. Aralıklar dışındaki kapsayıcılar için, kodun daha net okunmasını sağladığı için genellikle = yerine in veya anahtar kelimesi kullanılır.

julia> for i in [1,4,0]
           println(i)
       end
1
4
0

julia> for s ∈ ["foo","bar","baz"]
           println(s)
       end
foo
bar
baz

Farklı türdeki yineleyici konteynerler, kılavuzun ilerleyen bölümlerinde tanıtılacak ve tartışılacaktır (bkz. örneğin, Multi-dimensional Arrays).

Bir önceki while döngüsü biçimi ile for döngüsü biçimi arasındaki oldukça önemli bir ayrım, değişkenin görünür olduğu kapsamdır. Bir for döngüsü, kapsayıcı kapsamda aynı isimde bir değişken bulunsa bile, her zaman gövdesinde yeni bir yineleme değişkeni tanıtır. Bu, bir yandan i'nin döngüden önce tanımlanmasına gerek olmadığı anlamına gelir. Öte yandan, döngü dışında görünür olmayacak ve aynı isimdeki dış değişken de etkilenmeyecektir. Bunu test etmek için ya yeni bir etkileşimli oturum örneğine ya da farklı bir değişken adına ihtiyacınız olacak:

julia> for j = 1:3
           println(j)
       end
1
2
3

julia> j
ERROR: UndefVarError: `j` not defined in `Main`
julia> j = 0;

julia> for j = 1:3
           println(j)
       end
1
2
3

julia> j
0

for outer kullanarak son davranışı değiştirin ve mevcut bir yerel değişkeni yeniden kullanın.

Scope of Variables değişken kapsamı hakkında ayrıntılı bir açıklama için, outer ve Julia'da nasıl çalıştığı hakkında bilgi edinin.

Bazen, bir while döngüsünün test koşulu yanlışlanmadan önce tekrarı sonlandırmak veya bir for döngüsünde yineleyici nesnenin sonuna ulaşmadan önce yinelemeyi durdurmak pratik olabilir. Bu, break anahtar kelimesi ile gerçekleştirilebilir:

julia> i = 1;

julia> while true
           println(i)
           if i >= 3
               break
           end
           global i += 1
       end
1
2
3

julia> for j = 1:1000
           println(j)
           if j >= 3
               break
           end
       end
1
2
3

break anahtar kelimesi olmadan, yukarıdaki while döngüsü kendi başına asla sona ermeyecek ve for döngüsü 1000'e kadar dönecektir. Bu döngüler, break kullanılarak erken bir şekilde sonlandırılır.

Başka durumlarda, bir yinelemeyi durdurup hemen bir sonrakine geçebilmek faydalıdır. continue anahtar kelimesi bunu başarır:

julia> for i = 1:10
           if i % 3 != 0
               continue
           end
           println(i)
       end
3
6
9

Bu, durumu olumsuzlayarak ve println çağrısını if bloğunun içine yerleştirerek aynı davranışı daha net bir şekilde üretebileceğimiz için biraz yapay bir örnektir. Gerçekçi kullanımda, continue'dan sonra değerlendirilecek daha fazla kod vardır ve genellikle continue çağrısının yapıldığı birden fazla nokta vardır.

Birden fazla iç içe for döngüsü, dıştaki bir döngüde birleştirilerek, iterabl'larının kartezyen çarpımını oluşturabilir:

julia> for i = 1:2, j = 3:4
           println((i, j))
       end
(1, 3)
(1, 4)
(2, 3)
(2, 4)

Bu sözdizimi ile, yine de dış döngü değişkenlerine atıfta bulunabilen yinelemeler olabilir; örneğin, for i = 1:n, j = 1:i geçerlidir. Ancak, böyle bir döngü içinde bir break ifadesi, yalnızca iç döngüyü değil, tüm döngü kümesini terk eder. Her iç döngü çalıştığında, her iki değişken (i ve j) de mevcut yineleme değerlerine ayarlanır. Bu nedenle, i'ye yapılan atamalar sonraki yinelemelerde görünür olmayacaktır:

julia> for i = 1:2, j = 3:4
           println((i, j))
           i = 0
       end
(1, 3)
(1, 4)
(2, 3)
(2, 4)

Eğer bu örnek, her bir değişken için for anahtar kelimesi kullanılarak yeniden yazılsaydı, çıktı farklı olurdu: ikinci ve dördüncü değerler 0 içerirdi.

Birden fazla konteyner, tek bir for döngüsü içinde aynı anda yineleyebilir: zip

julia> for (j, k) in zip([1 2 3], [4 5 6 7])
           println((j,k))
       end
(1, 4)
(2, 5)
(3, 6)

zip kullanarak, ona geçirilen konteynerler için alt yineleyicileri içeren bir demet oluşturan bir yineleyici oluşturulacaktır. zip yineleyicisi, her for döngüsünün $i$'nci yinelemesinde her alt yineleyicinin $i$'nci elemanını seçerek, tüm alt yineleyiciler üzerinde sırayla yineleme yapacaktır. Herhangi bir alt yineleyici tükenirse, for döngüsü duracaktır.

Exception Handling

Beklenmedik bir durum meydana geldiğinde, bir fonksiyon çağrısına makul bir değer döndüremeyebilir. Bu tür durumlarda, olağanüstü durumun ya bir tanı hata mesajı yazdırarak programı sonlandırması ya da programcının bu tür olağanüstü durumları ele almak için kod sağlamışsa, o kodun uygun eylemi gerçekleştirmesine izin vermesi en iyisi olabilir.

Built-in Exceptions

Exceptionlar, beklenmedik bir durum meydana geldiğinde fırlatılır. Aşağıda listelenen yerleşik Exceptionlar, normal kontrol akışını kesintiye uğratır.

Exception
ArgumentError
BoundsError
CompositeException
DimensionMismatch
DivideError
DomainError
EOFError
ErrorException
InexactError
InitError
InterruptException
InvalidStateException
KeyError
LoadError
OutOfMemoryError
ReadOnlyMemoryError
RemoteException
MethodError
OverflowError
Meta.ParseError
SystemError
TypeError
UndefRefError
UndefVarError
StringIndexError

Örneğin, sqrt fonksiyonu, negatif bir reel değere uygulandığında DomainError hatası fırlatır:

julia> sqrt(-1)
ERROR: DomainError with -1.0:
sqrt was called with a negative real argument but will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
[...]

Kendi özel istisnalarınızı aşağıdaki şekilde tanımlayabilirsiniz:

julia> struct MyCustomException <: Exception end

The throw function

Ayrıcalıklar, throw ile açıkça oluşturulabilir. Örneğin, yalnızca negatif olmayan sayılar için tanımlanmış bir fonksiyon, negatif bir argüman varsa 4d61726b646f776e2e436f64652822222c20227468726f772229_40726566 bir DomainError olarak yazılabilir:

julia> f(x) = x>=0 ? exp(-x) : throw(DomainError(x, "argument must be non-negative"))
f (generic function with 1 method)

julia> f(1)
0.36787944117144233

julia> f(-1)
ERROR: DomainError with -1:
argument must be non-negative
Stacktrace:
 [1] f(::Int64) at ./none:1

DomainError parantezsiz bir istisna değildir, ancak bir istisna türüdür. Bir Exception nesnesi elde etmek için çağrılması gerekir:

julia> typeof(DomainError(nothing)) <: Exception
true

julia> typeof(DomainError) <: Exception
false

Ayrıca, bazı istisna türleri hata raporlaması için kullanılan bir veya daha fazla argüman alır:

julia> throw(UndefVarError(:x))
ERROR: UndefVarError: `x` not defined

Bu mekanizma, UndefVarError şeklinde yazıldığı gibi özel istisna türleri ile kolayca uygulanabilir:

julia> struct MyUndefVarError <: Exception
           var::Symbol
       end

julia> Base.showerror(io::IO, e::MyUndefVarError) = print(io, e.var, " not defined")
Note

Hata mesajı yazarken, ilk kelimenin küçük harfle başlaması tercih edilir. Örneğin,

size(A) == size(B) || throw(DimensionMismatch("A'nın boyutu B'nin boyutuna eşit değil"))

tercih edilir

size(A) == size(B) || throw(DimensionMismatch("A'nın boyutu B'nin boyutuna eşit değil")).

Ancak, bazen bir işlevin argümanı büyük harf ise, ilk harfi büyük tutmak mantıklıdır:

size(A,1) == size(B,2) || throw(DimensionMismatch("A'nın ilk boyutu...")).

Errors

error fonksiyonu, normal kontrol akışını kesen bir ErrorException üretmek için kullanılır.

Negatif bir sayının karekökü alındığında yürütmeyi hemen durdurmak istiyorsak, negatif bir argüman alındığında hata veren sqrt fonksiyonunun bulanık bir versiyonunu tanımlayabiliriz:

julia> fussy_sqrt(x) = x >= 0 ? sqrt(x) : error("negative x not allowed")
fussy_sqrt (generic function with 1 method)

julia> fussy_sqrt(2)
1.4142135623730951

julia> fussy_sqrt(-1)
ERROR: negative x not allowed
Stacktrace:
 [1] error at ./error.jl:33 [inlined]
 [2] fussy_sqrt(::Int64) at ./none:1
 [3] top-level scope

Eğer fussy_sqrt başka bir fonksiyondan negatif bir değerle çağrılırsa, çağıran fonksiyonun yürütülmesine devam etmeye çalışmak yerine hemen döner ve hata mesajını etkileşimli oturumda görüntüler:

julia> function verbose_fussy_sqrt(x)
           println("before fussy_sqrt")
           r = fussy_sqrt(x)
           println("after fussy_sqrt")
           return r
       end
verbose_fussy_sqrt (generic function with 1 method)

julia> verbose_fussy_sqrt(2)
before fussy_sqrt
after fussy_sqrt
1.4142135623730951

julia> verbose_fussy_sqrt(-1)
before fussy_sqrt
ERROR: negative x not allowed
Stacktrace:
 [1] error at ./error.jl:33 [inlined]
 [2] fussy_sqrt at ./none:1 [inlined]
 [3] verbose_fussy_sqrt(::Int64) at ./none:3
 [4] top-level scope

The try/catch statement

try/catch ifadesi, Exception'ların test edilmesine ve uygulamanızı normalde kırabilecek şeylerin zarif bir şekilde ele alınmasına olanak tanır. Örneğin, aşağıdaki kodda karekök fonksiyonu normalde bir istisna fırlatır. Bunu etrafında bir try/catch bloğu yerleştirerek burada hafifletebiliriz. Bu istisnayı nasıl ele alacağınızı seçebilirsiniz; bunu kaydetmek, bir yer tutucu değeri döndürmek veya aşağıdaki durumda olduğu gibi sadece bir ifade yazdırmak gibi. Beklenmedik durumları ele alırken düşünmeniz gereken bir şey, try/catch bloğu kullanmanın, bu durumları ele almak için koşullu dallanma kullanmaktan çok daha yavaş olduğudur. Aşağıda, try/catch bloğu ile istisnaları ele almanın daha fazla örneği bulunmaktadır:

julia> try
           sqrt("ten")
       catch e
           println("You should have entered a numeric value")
       end
You should have entered a numeric value

try/catch ifadeleri ayrıca Exception'ı bir değişkende saklamaya da olanak tanır. Aşağıdaki yapay örnek, x indekslenebilir ise x'in ikinci elemanının karekökünü hesaplar, aksi takdirde x'in bir reel sayı olduğunu varsayar ve karekökünü döndürür:

julia> sqrt_second(x) = try
           sqrt(x[2])
       catch y
           if isa(y, DomainError)
               sqrt(complex(x[2], 0))
           elseif isa(y, BoundsError)
               sqrt(x)
           end
       end
sqrt_second (generic function with 1 method)

julia> sqrt_second([1 4])
2.0

julia> sqrt_second([1 -4])
0.0 + 2.0im

julia> sqrt_second(9)
3.0

julia> sqrt_second(-9)
ERROR: DomainError with -9.0:
sqrt was called with a negative real argument but will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
[...]

catch ifadesinden sonraki sembolün her zaman istisna için bir ad olarak yorumlanacağını unutmayın, bu nedenle tek satırda try/catch ifadeleri yazarken dikkatli olunmalıdır. Aşağıdaki kod, bir hata durumunda x değerini döndürmek için çalışmayacaktır:

try bad() catch x end

Bunun yerine, catch ifadesinden sonra bir noktalı virgül kullanın veya bir satır sonu ekleyin:

try bad() catch; x end

try bad()
catch
    x
end

try/catch yapısının gücü, derinlemesine iç içe geçmiş bir hesaplamayı hemen çağıran fonksiyonlar yığınında çok daha yüksek bir seviyeye geri sarmak yeteneğinde yatmaktadır. Hata oluşmamış durumlar da vardır, ancak yığını geri sarmak ve bir değeri daha yüksek bir seviyeye iletmek istenebilir. Julia, daha gelişmiş hata yönetimi için rethrow, backtrace, catch_backtrace ve current_exceptions fonksiyonlarını sunmaktadır.

else Clauses

Julia 1.8

Bu işlevsellik en az Julia 1.8 gerektirir.

Bazen, birinin yalnızca hata durumunu uygun bir şekilde ele almakla kalmayıp, aynı zamanda try bloğu başarılı olduğunda yalnızca bazı kodları çalıştırmak istemesi mümkündür. Bunun için, daha önce herhangi bir hata atılmadığında çalıştırılan bir catch bloğundan sonra belirtilen bir else ifadesi kullanılabilir. Bu kodun try bloğuna dahil edilmesine göre avantajı, daha fazla hatanın catch ifadesi tarafından sessizce yakalanmamasıdır.

local x
try
    x = read("file", String)
catch
    # handle read errors
else
    # do something with x
end
Note

try, catch, else ve finally kısımları her biri kendi kapsam bloklarını tanıtır, bu nedenle bir değişken yalnızca try bloğunda tanımlanmışsa, else veya finally kısımları tarafından erişilemez:

julia> try
           foo = 1
       catch
       else
           foo
       end
ERROR: UndefVarError: `foo` not defined in `Main`
Suggestion: check for spelling errors or missing imports.

local keyword dışındaki try bloğunun, değişkenin dış kapsamda her yerden erişilebilir olmasını sağlamak için kullanın.

finally Clauses

Kodun durum değişiklikleri gerçekleştirdiği veya dosyalar gibi kaynaklar kullandığı durumlarda, genellikle kod tamamlandığında yapılması gereken temizleme işleri (örneğin dosyaları kapatma) vardır. İstisnalar bu görevi karmaşık hale getirebilir, çünkü bir kod bloğunun normal sonuna ulaşmadan çıkmasına neden olabilirler. finally anahtar kelimesi, belirli bir kod bloğu çıkarken, çıkış şekli ne olursa olsun bazı kodların çalıştırılmasını sağlar.

Örneğin, açılmış bir dosyanın kapatıldığından nasıl emin olabileceğimiz burada:

f = open("file")
try
    # operate on file f
finally
    close(f)
end

try bloğundan kontrol çıktığında (örneğin bir return nedeniyle veya normal bir şekilde sona erdiğinde), close(f) çalıştırılacaktır. Eğer try bloğu bir istisna nedeniyle çıkarsa, istisna yayılmaya devam edecektir. Bir catch bloğu try ve finally ile birleştirilebilir. Bu durumda finally bloğu, catch hatayı işledikten sonra çalışacaktır.

Tasks (aka Coroutines)

Görevler, hesaplamaların esnek bir şekilde askıya alınmasına ve yeniden başlatılmasına olanak tanıyan bir kontrol akışı özelliğidir. Tam bir tartışma için burada yalnızca tamamlayıcılık açısından bahsediyoruz; tam bir tartışma için bkz. Asynchronous Programming.