Ruby'de pattern matching, bir değerin yapısını case / in ifadesiyle kontrol edip eşleşen parçaları aynı anda yerel değişkenlere atamanızı sağlar. Dizi, hash, sınıf, aralık ve sabit değer desenlerini iç içe kullanabilir, ^ (pin) ile mevcut bir değişkenin değerini desene koyabilir, if ile ek koşul ekleyebilirsiniz. Tek satırlık => biçimi eşleşmezse hata fırlatır, in biçimi ise yalnızca true veya false döndürür.
Bu yazı Ruby 4.0 belgelerindeki pattern matching bölümünü temel alır ve her deseni çalıştırılmış örneklerle anlatır. Klasik case / when kullanımını henüz bilmiyorsanız önce Ruby if, unless ve case yazısına, genel bir yol haritası için Ruby öğrenme rehberi sayfasına bakabilirsiniz.
case / in ile ilk eşleşme

case / in ifadesi dalları sırayla dener ve eşleşen ilk dalı çalıştırır. when dallarından farklı olarak burada desen yalnızca değeri karşılaştırmaz, yapıyı da çözer. Belgelere göre aynı case içinde in ve when dallarını karıştıramazsınız. Hiçbir dal eşleşmezse ve else yoksa NoMatchingPatternError fırlatılır; bu yüzden ifade "kapsayıcı" kabul edilir.
def tarif_et(veri)
case veri
in Integer | Float => sayi if sayi.negative?
"negatif sayı: #{sayi}"
in Integer | Float
"sayı"
in String
"metin"
in []
"boş dizi"
in [x]
"tek elemanlı dizi: #{x}"
in {ad: String => ad}
"ad alanı olan hash: #{ad}"
else
"tanınmadı"
end
end
p tarif_et(-3)
p tarif_et(2.5)
p tarif_et("merhaba")
p tarif_et([])
p tarif_et([7])
p tarif_et({ad: "Elif", yas: 30})
p tarif_et(nil)
# çıktı: "negatif sayı: -3"
# çıktı: "sayı"
# çıktı: "metin"
# çıktı: "boş dizi"
# çıktı: "tek elemanlı dizi: 7"
# çıktı: "ad alanı olan hash: Elif"
# çıktı: "tanınmadı"Bu kısa örnek birkaç desen türünü bir arada kullanıyor: Integer | Float alternatif desen, => sayi eşleşen değeri değişkene bağlayan "as" deseni, if ise guard koşuludur. Aşağıda her birini ayrı ayrı ele alıyoruz.
Değer desenleri: sınıflar, aralıklar ve sabitler
Bir desen yerine herhangi bir Ruby nesnesi yazdığınızda karşılaştırma === operatörüyle yapılır, tıpkı when dallarında olduğu gibi. Böylece sınıflar (Integer === 5), aralıklar ((1..10) === 5) ve düzenli ifadeler doğal olarak desen olarak çalışır. Kısa dallar için then ile tek satır yazabilirsiniz.
def not_harfi(puan)
case puan
in 85..100 then "AA"
in 70...85 then "BB"
in 50...70 then "CC"
in 0...50 then "FF"
end
end
p not_harfi(92)
p not_harfi(64)
begin
not_harfi(150)
rescue NoMatchingPatternError => e
puts "#{e.class}: #{e.message}"
end
# çıktı: "AA"
# çıktı: "CC"
# çıktı: NoMatchingPatternError: 150Son çağrıda hiçbir dal eşleşmediği ve else olmadığı için istisna oluştu. Beklenmeyen girdinin sessizce geçmesini istemediğiniz yerlerde bu davranış işinize yarar; istemiyorsanız bir else dalı ekleyin. Aralıkların ayrıntısı için Ruby range yazısına bakabilirsiniz.
Dizi desenleri ve find pattern
Dizi deseni, dizinin tamamıyla eşleşir: [Integer, Integer] üç elemanlı bir diziyle eşleşmez. Kalan elemanları kabul etmek için *, bunları bir değişkende toplamak için *kalan yazarsınız. Köşeli parantezleri çoğu zaman atlayabilirsiniz.
komut = ["kopyala", "a.txt", "b.txt", "--zorla"]
case komut
in ["sil", dosya]
puts "Silinecek: #{dosya}"
in ["kopyala", kaynak, hedef, *secenekler]
puts "#{kaynak} -> #{hedef}, seçenekler: #{secenekler}"
end
# çıktı: a.txt -> b.txt, seçenekler: ["--zorla"]Find pattern ise dizinin herhangi bir yerinde, art arda gelen elemanları arar. Desenin iki ucuna * koyarsınız; isterseniz bu uçlara isim vererek eşleşmenin öncesini ve sonrasını da alabilirsiniz. Ruby 3.2 NEWS dosyasına göre find pattern artık deneysel değildir.
olaylar = [
{tur: "giris", kullanici: "ali"},
{tur: "hata", kod: 500},
{tur: "cikis", kullanici: "ali"}
]
case olaylar
in [*onceki, {tur: "hata", kod:}, *sonraki]
puts "Hata kodu: #{kod}"
puts "Öncesinde #{onceki.size}, sonrasında #{sonraki.size} olay var"
end
# çıktı: Hata kodu: 500
# çıktı: Öncesinde 1, sonrasında 1 olay varHash desenleri

Hash deseni dizi deseninin tersine kısmi eşleşir: desende yazmadığınız anahtarlar olsa da eşleşme başarılı olur. Yalnızca belirttiğiniz anahtarların bulunmasını istiyorsanız sona **nil eklersiniz; geri kalan anahtarları almak için **kalan yazarsınız. ad: gibi değersiz bir anahtar, aynı adlı bir yerel değişken oluşturur. Belgelerin vurguladığı önemli bir kısıt: hash desenlerinde yalnızca sembol anahtarlar desteklenir. Boş desen {} ise istisnadır ve yalnızca boş hash ile eşleşir.
yanit = {durum: 200, veri: {kullanici: {ad: "Can", rol: "admin"}}, sure: 0.12}
case yanit
in {durum: 200, veri: {kullanici: {rol: "admin", ad:}}}
puts "Yönetici: #{ad}"
in {durum: 400..499 => kod}
puts "İstemci hatası: #{kod}"
end
kisi = {ad: "Deniz", yas: 28, sehir: "İzmir"}
p((kisi in {ad: String}))
p((kisi in {ad: String, **nil}))
p(({"ad" => "Deniz"} in {ad: String}))
case kisi
in {ad:, **diger}
p ad
p diger
end
# çıktı: Yönetici: Can
# çıktı: true
# çıktı: false
# çıktı: false
# çıktı: "Deniz"
# çıktı: {yas: 28, sehir: "İzmir"}Değişken bağlama ve pin operatörü (^)
Desende yalın bir isim yazdığınızda Ruby onu "buraya ne gelirse bu değişkene ata" olarak yorumlar. Bu yüzden mevcut bir değişkeni desene doğrudan yazmak, onun değeriyle karşılaştırma yapmaz; değişkenin üzerine yazar. Değeri desende kullanmak için başına ^ koyarsınız. Pin operatörü yerel değişkenlerin yanında örnek, sınıf ve genel değişkenlerle de çalışır; ^(ifade) biçimiyle herhangi bir ifadenin sonucunu da sabitleyebilirsiniz.
beklenen = 18
case 25
in beklenen
puts "Eşleşti, beklenen artık #{beklenen}"
end
beklenen_kod = 404
case {durum: 404, yol: "/blog"}
in {durum: ^beklenen_kod, yol:}
puts "Bulunamadı: #{yol}"
end
case [3, 3]
in [a, ^a]
puts "İki eleman aynı: #{a}"
end
limit = 10
case 15
in ^(limit + 5)
puts "Tam olarak limit + 5"
end
# çıktı: Eşleşti, beklenen artık 25
# çıktı: Bulunamadı: /blog
# çıktı: İki eleman aynı: 3
# çıktı: Tam olarak limit + 5İlk örnek tipik bir tuzaktır: in beklenen her değerle eşleşir ve beklenen değişkenine 25 atanır. Üçüncü örnekte ise aynı desen içinde önce bağlanan a, ikinci konumda pin ile tekrar kullanılıyor; böylece "iki eleman eşit mi" kontrolü tek desende yapılıyor.
Guard koşulları: if ve unless
Desen eşleştikten sonra ek bir koşul kontrol etmek için dalın sonuna if veya unless yazarsınız. Koşul, desenin bağladığı değişkenleri kullanabilir. Koşul sağlanmazsa Ruby bir sonraki dala geçer.
def kontrol(cift)
case cift
in [a, b] if b == a * 2 then "ikincisi birincinin iki katı"
in [a, b] unless a == b then "farklı sayılar"
in [_, _] then "eşit sayılar"
end
end
p kontrol([3, 6])
p kontrol([3, 5])
p kontrol([4, 4])
# çıktı: "ikincisi birincinin iki katı"
# çıktı: "farklı sayılar"
# çıktı: "eşit sayılar"Belgelere göre guard koşulu yalnızca case / in dallarında geçerlidir. Tek satırlık => ve in biçimlerinin sonuna yazılan if, guard olarak değil, satırın tamamına uygulanan sıradan bir if değiştiricisi olarak yorumlanır.
Tek satırlık biçimler: => ve in
Verinin yapısını önceden biliyorsanız ve yalnızca parçalarını çıkarmak istiyorsanız ifade => desen biçimi kısa ve nettir. Eşleşme başarısız olursa istisna fırlatılır; hash deseninde eksik bir anahtar yüzünden başarısız olduğunda bu istisna NoMatchingPatternKeyError olur ve key metodu eksik anahtarı verir. ifade in desen ise yalnızca eşleşip eşleşmediğini söyler; belgelere göre bu, true / false döndüren bir case ifadesiyle aynıdır.
ayar = {db: {kullanici: "admin", port: 5432}}
ayar => {db: {kullanici:, port:}}
puts "#{kullanici}@#{port}"
kullanicilar = [{ad: "Ayşe", yas: 17}, {ad: "Burak", yas: 23}]
p kullanicilar.select { it in {yas: 18..} }.map { it[:ad] }
begin
ayar => {cache: {ttl:}}
rescue NoMatchingPatternKeyError => e
puts e.class
p e.key
end
# çıktı: admin@5432
# çıktı: ["Burak"]
# çıktı: NoMatchingPatternKeyError
# çıktı: :cacheÖrnekteki it, Ruby 3.4 ile gelen örtük blok parametresidir; ayrıntısı Ruby blok parametreleri: it ve numaralı yazısında. Ruby 3.1 NEWS dosyasına göre tek satırlık pattern matching artık deneysel değildir ve desen etrafındaki parantezler atlanabilir.
Kendi sınıflarınızla eşleşme: deconstruct ve deconstruct_keys
Dizi ve find desenleri, dizi olmayan bir nesneyle karşılaştığında onun deconstruct metodunu; hash desenleri ise deconstruct_keys metodunu çağırır. Bu iki metodu tanımlayarak kendi sınıfınızı desenlerle kullanılabilir hale getirirsiniz. Desenin başına sınıf adını yazarak Nokta(x:, y:) veya Nokta[x, y] biçiminde tür kontrolünü de aynı adımda yapabilirsiniz; sınıf kontrolü === ile yapılır.
class Nokta
attr_reader :x, :y
def initialize(x, y)
@x = x
@y = y
end
def deconstruct = [x, y]
def deconstruct_keys(keys) = {x: x, y: y}
end
def konum(nokta)
case nokta
in Nokta(x: 0, y: 0) then "orijin"
in Nokta(x: 0) then "y ekseni üzerinde"
in Nokta[x, 0] then "x ekseni üzerinde, x = #{x}"
in Nokta(x:, y:) if x == y then "köşegen üzerinde"
else "başka bir yerde"
end
end
[[0, 0], [0, 5], [3, 0], [2, 2], [1, 4]].each do |x, y|
puts konum(Nokta.new(x, y))
end
# çıktı: orijin
# çıktı: y ekseni üzerinde
# çıktı: x ekseni üzerinde, x = 3
# çıktı: köşegen üzerinde
# çıktı: başka bir yerdedeconstruct_keys metoduna verilen keys argümanı, desenin hangi anahtarları istediğini söyler. Tam hash'i hesaplamak pahalıysa yalnızca istenenleri döndürebilirsiniz. Desende **kalan kullanıldığında ise tüm anahtarlar gerekebileceği için nil gönderilir:
class Kayit
def deconstruct_keys(keys)
puts "istenen anahtarlar: #{keys.inspect}"
{id: 1, ad: "test", gizli: "x"}
end
end
case Kayit.new
in {id:, ad:} then puts "id=#{id}"
end
case Kayit.new
in {id:, **geri} then p geri
end
# çıktı: istenen anahtarlar: [:id, :ad]
# çıktı: id=1
# çıktı: istenen anahtarlar: nil
# çıktı: {ad: "test", gizli: "x"}Çekirdekte bu metotları hazır sunan sınıflar da var. Belgeler MatchData#deconstruct ve MatchData#deconstruct_keys ile Time, Date ve DateTime sınıflarının deconstruct_keys metodunu sayar. Böylece bir düzenli ifade eşleşmesini doğrudan hash deseniyle açabilirsiniz; adlandırılmış gruplar sembol anahtar olarak gelir. Düzenli ifadelerin ayrıntısı Ruby Regexp yazısında.
case /(?<yil>\d{4})-(?<ay>\d{2})/.match("Rapor 2026-11")
in {yil:, ay:}
puts "Yıl #{yil}, ay #{ay}"
end
# çıktı: Yıl 2026, ay 11Değer nesnesi tanımlamak için kullanılan Struct ve Data sınıflarını Ruby Struct ve Data sınıfı yazısında ele alıyoruz.
Desen türleri özeti
| Desen | Örnek | Ne yapar |
|---|---|---|
| Değer | in 1..10, in String | Değeri === ile karşılaştırır |
| Dizi | in [a, b, *kalan] | Dizinin tamamıyla eşleşir |
| Find | in [*, {tur: "hata"}, *] | Dizinin içinde ardışık parçayı arar |
| Hash | in {ad:, yas: Integer} | Kısmi eşleşir, yalnızca sembol anahtar |
| Alternatif | in Integer | Float | Seçeneklerden biri tutarsa eşleşir |
| As (bağlama) | in Integer => n | Eşleşen değeri değişkene atar |
| Pin | in ^beklenen | Mevcut değişkenin değerini kullanır |
| Guard | in [a, b] if a < b | Eşleşmeden sonra ek koşul |
| Sınıf ile | in Nokta(x:, y:) | Tür kontrolü ve çözümleme birlikte |
Sürüm notları
NEWS dosyalarına göre case / in Ruby 3.0 ile deneysel olmaktan çıktı; tek satırlık biçim 3.1'de, find pattern 3.2'de kalıcı hale geldi. MatchData#deconstruct ve MatchData#deconstruct_keys da 3.2 ile eklendi. Ruby 4.0 NEWS dosyası pattern matching söz dizimi için yeni bir değişiklik listelemiyor; yukarıdaki örneklerin tamamı Ruby 4.0.9 ile çalıştırıldı.
Sık yapılan hatalar

- Pin unutmak: Mevcut bir değişkeni desene
^olmadan yazmak karşılaştırma yapmaz, değişkenin üzerine yazar ve her değerle eşleşir. - Diziyi kısmi sanmak:
[a, b]deseni üç elemanlı diziyle eşleşmez. Fazlasını kabul etmek için*ekleyin. - Metin anahtarlı hash:
{"ad" => "x"}verisi{ad:}deseniyle eşleşmez; hash desenleri yalnızca sembol anahtarlarla çalışır. - else unutmak: Hiçbir dal tutmazsa
NoMatchingPatternErroroluşur. Bu bilinçli bir tercih değilseelseekleyin. - Alternatifte bağlama:
in {a:} | Arraygibi bir desenSyntaxErrorverir. - when ile karıştırmak: Aynı
caseiçinde hemwhenheminkullanılamaz.
Sık Sorulan Sorular
case / when ile case / in arasındaki fark nedir?
when değeri === ile karşılaştırır ve yalnızca evet ya da hayır der. in ise aynı karşılaştırmayı yaparken yapıyı da çözer, iç içe dizi ve hash'lere bakar ve eşleşen parçaları değişkenlere bağlar. Ayrıca case / in hiçbir dal tutmadığında istisna fırlatır, case / when ise nil döndürür.
=> ile in arasında hangisini seçmeliyim?
Veri yapısının belli olduğunu varsayıyor ve aksi durumda programın hata vermesini istiyorsanız => kullanın. Sadece kontrol yapmak, örneğin select içinde süzmek istiyorsanız in kullanın; o hiçbir zaman eşleşme hatası fırlatmaz.
Hash deseninde metin anahtar kullanabilir miyim?
Hayır, belgelere göre hash desenleri yalnızca sembol anahtarları destekler. Metin anahtarlı bir hash'i önce transform_keys(&:to_sym) gibi bir dönüşümle sembol anahtarlı hale getirebilirsiniz.
Kendi sınıfım için hangi metodu yazmalıyım?
Dizi ve find desenleri için deconstruct (dizi döndürür), hash desenleri için deconstruct_keys(keys) (sembol anahtarlı hash döndürür). İkisini birden tanımlarsanız sınıfınız her iki desen türüyle de kullanılabilir.
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 if, unless ve case · Ruby hash metotları · Ruby array metotları · Ruby Struct ve Data · Ruby Regexp · Ruby hata yönetimi