Ruby'de koşullar if, elsif, else, unless, case/when ve ? : üçlü operatörüyle yazılır. En önemli kural şudur: koşul sınanırken yalnızca nil ve false yanlış sayılır; 0, boş metin "" ve boş dizi [] dahil diğer bütün değerler doğrudur. Ayrıca Ruby'deki tüm koşul yapıları birer ifadedir ve bir değer döndürür.

Bu yazıda koşul yapılarının her birini, tek satırlık modifier biçimleri, case ifadesinin arka planda kullandığı === eşleşmesini ve sık yapılan hataları Control Expressions belgesi temelinde anlatıyoruz. Örneklerin tamamı Ruby 4.0 ile çalıştırıldı. Serinin diğer konuları Ruby öğrenme rehberi sayfasında.

Doğruluk kuralı: yalnızca nil ve false yanlıştır

Doğruluk kuralı: yalnızca nil ve false yanlıştır

Başka dillerden gelenler için en şaşırtıcı nokta, 0 ve boş koleksiyonların doğru sayılmasıdır. Aşağıdaki döngü her değeri bir koşulda sınar:

ruby
[nil, false, true, 0, "", [], {}, "false"].each do |deger|
  sonuc = deger ? "doğru" : "yanlış"
  puts "#{deger.inspect}: #{sonuc}"
end
# Çıktı:
# nil: yanlış
# false: yanlış
# true: doğru
# 0: doğru
# "": doğru
# []: doğru
# {}: doğru
# "false": doğru

Bir değerin sıfır, boş veya nil olup olmadığını sınamak istiyorsanız koşula değeri doğrudan yazmak yerine açık bir metot kullanın: sayi.zero?, metin.empty?, liste.empty?, deger.nil?. Bu metotlar sonucu her zaman true veya false olarak verir.

ruby
p 0.zero?       # çıktı: true
p "".empty?     # çıktı: true
p [].empty?     # çıktı: true
p nil.nil?      # çıktı: true
p 5.nil?        # çıktı: false

if, elsif ve else

if koşulu doğruysa gövdesini çalıştırır. Birden fazla koşul için elsif eklenir (else if değil); bir koşul eşleştiği anda geri kalanlar sınanmaz. Hiçbiri eşleşmezse else çalışır. if ifadesinin değeri, çalışan daldaki son ifadedir; hiçbir dal çalışmazsa değer nil olur. Bu yüzden bir metodun son ifadesi olarak if yazmak, o metodun dönüş değerini belirler.

ruby
def not_harfi(puan)
  if puan >= 85
    "A"
  elsif puan >= 70
    "B"
  elsif puan >= 50
    "C"
  else
    "F"
  end
end

p not_harfi(92)   # çıktı: "A"
p not_harfi(70)   # çıktı: "B"
p not_harfi(12)   # çıktı: "F"

sonuc = if false then "çalışmaz" end
p sonuc           # çıktı: nil

then anahtar kelimesi isteğe bağlıdır; çoğunlukla koşulu ve gövdeyi tek satırda yazmak için kullanılır: if x > 0 then "pozitif" end. Metotların dönüş değeri hakkında daha fazlası Ruby metot tanımlama yazısında.

unless: if not yerine

unless, if ifadesinin tersidir: koşul yanlışsa gövdeyi çalıştırır. else dalı eklenebilir, ancak belgelerin belirttiği gibi unless ile elsif kullanılamaz. Olumsuz bir koşulu okunaklı biçimde yazmak için uygundur; else dalı gerekiyorsa koşulu tersine çevirip if kullanmak genellikle daha anlaşılırdır.

ruby
stok = 0

unless stok.positive?
  puts "Stokta yok"    # çıktı: Stokta yok
else
  puts "Stokta var"
end

Modifier biçim: tek satırda koşul

if ve unless bir ifadenin sonuna eklenerek tek satırlık koşul yazılabilir. Bu biçimde soldaki kod yalnızca sağdaki koşul sağlanırsa çalışır. Metotların başında erken dönüş (guard clause) için çok kullanılır:

ruby
bakiye = 120
puts "Bakiye yeterli" if bakiye >= 100       # çıktı: Bakiye yeterli
puts "Bakiye düşük" unless bakiye >= 100

def bol(a, b)
  return nil if b.zero?
  a / b
end

p bol(10, 2)   # çıktı: 5
p bol(10, 0)   # çıktı: nil

Modifier biçimin bir başka sınırı daha vardır: belgelere göre modifier if bir deyimdir (statement), ifade (expression) değildir. Bu yüzden puts( 1 if true ) satırı SyntaxError verir. Deyimi ifade gibi kullanmak için ikinci bir parantez gerekir:

ruby
puts((1 if true))    # çıktı: 1
x = (5 if false)
p x                  # çıktı: nil

Üçlü operatör: koşul ? a : b

Kısa bir if/else ifadesi koşul ? doğruysa : yanlışsa biçiminde tek satırda yazılabilir. Belgeler okunabilirlik için üçlü operatörü yalnızca basit koşullarda kullanmayı ve aynı ifadede birden fazla üçlü operatörü iç içe yazmaktan kaçınmayı önerir.

ruby
adet = 0
durum = adet.zero? ? "sepet boş" : "#{adet} ürün var"
p durum   # çıktı: "sepet boş"

adet = 3
puts adet.zero? ? "sepet boş" : "#{adet} ürün var"   # çıktı: 3 ürün var

case ve when

case ve when: Konusuz case, case ve in: desen eşleştirme

case bir değeri sırayla birden fazla koşulla karşılaştırır ve ilk eşleşen when dalını çalıştırır. Karşılaştırma == ile değil, === ile yapılır ve when içindeki değer solda durur: when Integer dalı için Ruby Integer === deger çağırır. Bu sayede aynı case içinde sınıflar, aralıklar, düzenli ifadeler ve düz değerler kullanılabilir. Bir when satırına virgülle birden fazla koşul yazılabilir.

ruby
def tanimla(deger)
  case deger
  when nil            then "boş değer"
  when Integer, Float then "sayı"
  when /\A\d{5}\z/    then "posta koduna benzeyen metin"
  when String         then "metin"
  else                     "başka bir şey"
  end
end

p tanimla(42)        # çıktı: "sayı"
p tanimla(3.5)       # çıktı: "sayı"
p tanimla("35210")   # çıktı: "posta koduna benzeyen metin"
p tanimla("Ruby")    # çıktı: "metin"
p tanimla(nil)       # çıktı: "boş değer"
p tanimla([1])       # çıktı: "başka bir şey"

Dalların sırası önemlidir: "35210" hem düzenli ifadeye hem String sınıfına uyar, ama ilk eşleşen dal kazanır. Aralıklarla case yazmak, sayısal eşikleri olan kurallar için oldukça okunaklıdır:

ruby
def kargo_ucreti(kg)
  case kg
  when 0...1 then 30
  when 1...5 then 55
  when 5..20 then 90
  end
end

p kargo_ucreti(0.4)   # çıktı: 30
p kargo_ucreti(5)     # çıktı: 90
p kargo_ucreti(25)    # çıktı: nil
when içindeki değerÇağrılanAnlamı
Integer (sınıf)Integer === xx bu sınıfın örneği mi
1..10 (aralık)(1..10) === xx aralıkta mı
/desen/ (Regexp)/desen/ === xx metni desene uyuyor mu
"metin" (String)"metin" === xx bu metne eşit mi
->(n) { ... } (lambda)lambda === xlambda x ile çağrılınca doğru mu

Son satırdaki lambda kullanımı, karmaşık koşulları adlandırmanın kısa bir yoludur:

ruby
cift = ->(n) { n.even? }

case 8
when cift then puts "çift sayı"   # çıktı: çift sayı
else           puts "tek sayı"
end

Konusuz case

case anahtar kelimesinden sonra değer yazılmazsa her when kendi koşulunu sınar ve yapı bir if/elsif zinciri gibi çalışır. case de bir ifade olduğu için sonucu doğrudan bir değişkene atanabilir:

ruby
sicaklik = 8
yagmur = true

oneri = case
        when sicaklik < 0 then "evde kalın"
        when yagmur       then "şemsiye alın"
        else                   "yürüyüşe çıkın"
        end

p oneri   # çıktı: "şemsiye alın"

case ve in: desen eşleştirme

Ruby 2.7'den beri case ifadesi when yerine in ile de yazılabilir. Bu biçim değerin yapısını bir desenle karşılaştırır ve eşleşen parçaları değişkenlere bağlar. Kapsamlı anlatım Ruby pattern matching yazısında; burada yalnızca bir örnek veriyoruz:

ruby
yanit = { durum: "ok", veri: { id: 7 } }

case yanit
in { durum: "ok", veri: { id: Integer => id } }
  puts "kayıt #{id}"   # çıktı: kayıt 7
in { durum: "hata" }
  puts "hata"
end

Koşul içinde değer saklamak

Control Expressions belgesi, if ve elsif testlerinin yan etkili olabileceğini ve bunun en yaygın kullanımının bir değeri yerel değişkene saklamak olduğunu belirtir. Bir metot bulamadığında nil döndürüyorsa, sonucu koşul içinde bir değişkene atayıp aynı anda doğruluğunu sınayabilirsiniz. Atamanın bilinçli olduğunu okuyucuya göstermek için parantez içine almak iyi bir alışkanlıktır; sabit bir değerin atandığı if x = 5 gibi durumlarda Ruby zaten found '= literal' in conditional, should be == uyarısı verir.

ruby
def bul(id)
  { 1 => "Ayşe", 2 => "Can" }[id]
end

if (ad = bul(2))
  puts "Bulundu: #{ad}"   # çıktı: Bulundu: Can
end

if (ad = bul(9))
  puts "Bulundu: #{ad}"
else
  puts "Kayıt yok"        # çıktı: Kayıt yok
end

Hash'te olmayan bir anahtar nil döndürdüğü için ikinci koşul yanlış sayılır ve else dalı çalışır. Aynı kalıp, düzenli ifade eşleşmelerinde (if (m = metin.match(desen))) de sık kullanılır.

Uzun koşulları bölmek

Birden fazla şartı birleştirirken && ve || kullanılır; ayrıntılar Ruby operatörler ve öncelik yazısında. Ruby 4.0 ile bu operatörler satır başına yazılarak önceki satırın devamı sayılabiliyor; NEWS dosyası bunu satır başında noktayla yazılan metot zincirlerine benzetir. Kodunuz eski sürümlerde de çalışacaksa operatörü satır sonunda bırakın.

ruby
kayitli = true
aktif = true
yas = 20

if kayitli
   && aktif
   && yas >= 18
  puts "işlem onaylandı"   # çıktı: işlem onaylandı
end

Sık yapılan hatalar

Sık yapılan hatalar: 0 veya boş metni yanlış sanmak, else if yazmak, Koşulda = ile == karıştırmak, when içinde sırayı ters düşünmek
  • 0 veya boş metni yanlış sanmak: if liste boş bir dizi için de doğrudur. liste.empty? veya liste.any? kullanın.
  • else if yazmak: Ruby'de doğru anahtar kelime elsif'tir. else if yazarsanız iç içe yeni bir if açılır ve fazladan bir end gerekir.
  • Koşulda = ile == karıştırmak: if x = 5 bir karşılaştırma değil atamadır ve her zaman doğrudur; Ruby bu durumda bir uyarı da verir.
  • when içinde sırayı ters düşünmek: case çağrıyı when_degeri === konu biçiminde yapar; String === "a" doğrudur, "a" === String yanlıştır.
  • unless ile else ve olumsuz koşulları birleştirmek: unless !hazir gibi çift olumsuzluk okumayı zorlaştırır; if hazir yazın.

Sık Sorulan Sorular

Ruby'de truthy ve falsy değerler nelerdir?

Yanlış sayılan yalnızca iki değer vardır: nil ve false. 0, 0.0, "", [], {} ve "false" metni dahil diğer bütün nesneler koşullarda doğru sayılır.

case ile if/elsif arasında hangisini seçmeliyim?

Tek bir değeri birden fazla olasılıkla karşılaştırıyorsanız case daha kısadır ve === sayesinde sınıf, aralık ve desen eşleşmesini de kendiliğinden yapar. Birbirinden bağımsız koşulları sınıyorsanız if/elsif veya konusuz case kullanın.

Ruby'de switch var mı?

Ruby'de switch anahtar kelimesi yoktur; aynı işi case/when görür. Diğer dillerdeki break ihtiyacı da yoktur, çünkü yalnızca ilk eşleşen dal çalışır ve sonraki dallara geçilmez.

if ifadesinin değerini bir değişkene atayabilir miyim?

Evet. if, unless ve case ifadeleri, çalışan daldaki son ifadenin değerini döndürür. durum = if x > 0 then "pozitif" else "negatif" end geçerli bir Ruby kodudur. Hiçbir dal çalışmazsa değer nil olur.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Ruby öğrenme rehberi · Ruby döngüler · Ruby operatörler ve öncelik · Ruby pattern matching · Ruby metot tanımlama