Ruby'de blok parametreleri |x| gibi açıkça adlandırılabilir ya da kısa bloklarda adsız bırakılabilir. Adsız kullanımda iki seçenek var: tek parametreli bloklar için it ve birden fazla parametre için _1, _2 ... _9 numaralı parametreleri. NEWS dosyalarına göre numaralı parametreler Ruby 2.7 ile, it ise Ruby 3.4 ile geldi. Bir blokta açık parametre, it ve numaralı parametreler birbirleriyle karıştırılamaz.

Bu yazıda önce açık blok parametrelerinin yazım seçeneklerini (parçalama, splat, varsayılan değer, blok-yerel değişken), sonra it ve _1 kullanımını ve kurallarını anlatıyoruz. Hatalı kullanımlarda Ruby'nin verdiği gerçek SyntaxError mesajlarını da gösteriyoruz. Örnekler Ruby 4.0 ile çalıştırıldı. Blokların genel mantığı için blok ve yield yazısına bakabilirsiniz.

Açık blok parametreleri

Açık blok parametreleri

Belgelere göre blok parametreleri metot parametrelerine benzer biçimde tanımlanır. Bu yüzden birden fazla parametre, parantezle iç içe parçalama, * ile kalanları toplama, varsayılan değer ve keyword parametresi kullanabilirsiniz. Hash üzerinde each çağrıldığında her eleman anahtar ve değerden oluşan bir çifttir; iki parametre yazarsanız çift kendiliğinden ayrılır.

ruby
stok = { elma: 3, armut: 0 }
stok.each { |ad, adet| puts "#{ad}: #{adet}" }
# çıktı: elma: 3
# çıktı: armut: 0

p [[1, [2, 3]], [4, [5, 6]]].map { |a, (b, c)| a + b + c } # çıktı: [6, 15]
p [[1, 2, 3, 4]].map { |ilk, *kalan| kalan }               # çıktı: [[2, 3, 4]]
p [1, 2].map { |x, carpan = 10| x * carpan }               # çıktı: [10, 20]
p [3].map { |x, olcek: 2| x * olcek }                      # çıktı: [6]

Parametre listesinde ; işaretinden sonra yazılan adlar ise blok-yerel değişkendir: |x; gecici| yazarsanız gecici dıştaki aynı adlı değişkeni etkilemez. Bu özellik blok ve yield yazısında örnekle anlatılıyor.

it: tek parametreli bloklar için

it, açık parametre tanımlanmamış bir bloğun içinde bloğun ilk ve tek parametresini temsil eder. Ruby 3.4 NEWS dosyası bu özelliği "bir blok parametresine başvurmak için it eklendi" diye duyurur. Bir önceki sürüm olan Ruby 3.3, argümansız ve parametresiz bloklarda it çağrılarını kullanımdan kaldırılacak (deprecated) olarak işaretlemiş ve 3.4'te ilk blok parametresine başvuracağını önceden bildirmişti.

ruby
p %w[ali ece].map { it.capitalize } # çıktı: ["Ali", "Ece"]
p (1..4).map { it * it }            # çıktı: [1, 4, 9, 16]

Belgeler it için "soft keyword" ifadesini kullanır: ayrılmış bir kelime değildir, metot ya da yerel değişken adı olarak kullanılabilir. Örneğin RSpec benzeri bir it metodu tanımlamak uyarı üretmez. Aynı adda bir yerel değişken varsa ve blok açık parametre tanımlıyorsa, it o değişkeni ifade eder. it kullanan bloklar iç içe de yazılabilir; her it kendi bloğunun parametresini gösterir.

ruby
%w[ab cd].each { it.each_char { print it } }
puts
# çıktı: abcd

it = 5
[1, 2].each { |x| p it }
# çıktı: 5
# çıktı: 5

Numaralı parametreler: _1, _2 ... _9

Numaralı parametreler, bloğun birden fazla parametresine adsız erişmenizi sağlar. Ruby 2.7 NEWS dosyası bunları "varsayılan blok parametreleri" olarak tanıtır. Belgelere göre _1'den _9'a kadar adlar desteklenir, ancak okunabilirlik için kendinizi _1 ve _2 ile ve tek satırlık bloklarla sınırlamanız önerilir.

ruby
p %w[ali ece].map { _1.capitalize }            # çıktı: ["Ali", "Ece"]
p({ a: 100, b: 200 }.map { "#{_1} = #{_2}" })   # çıktı: ["a = 100", "b = 200"]
p [[1, 2], [3, 4]].map { _1 + _2 }              # çıktı: [3, 7]

_1 tek başına ile it arasındaki ince nokta

Ruby 4.0 ile yaptığımız denemede, blokta yalnızca _1 kullanıldığında blok tek parametreli bir blok gibi davrandı ve iç diziler parçalanmadı; it ile aynı sonucu verdi. _2 de kullanıldığında ise blok iki parametreli hâle geldi ve her çift parçalandı. Yani _1'in değeri, blokta başka hangi numaralı parametreyi kullandığınıza göre değişebilir.

ruby
p [[1, 2], [3, 4]].map { it } # çıktı: [[1, 2], [3, 4]]
p [[1, 2], [3, 4]].map { _1 } # çıktı: [[1, 2], [3, 4]]
p [[1, 2], [3, 4]].map { _1 + _2 } # çıktı: [3, 7]

Kurallar ve SyntaxError mesajları

Kurallar ve SyntaxError mesajları: Açık parametresi olan bir blokta it kullanılamaz (aynı adda yerel değişken..., Numaralı parametreler açık parametrelerle de birlikte...

Adsız parametrelerle ilgili kuralların hepsi derleme aşamasında denetlenir; kural ihlali programın hiç çalışmamasına yol açan bir SyntaxError üretir. Aşağıdaki satırların her biri ayrı bir dosyada Ruby 4.0 ile çalıştırıldı; yorumlar hata mesajının ana satırıdır.

ruby
[1, 2, 3].each { |x| p it }
# SyntaxError: 'it' is not allowed when an ordinary parameter is defined

[10, 20].map { _1 + it }
# SyntaxError: 'it' is not allowed when a numbered parameter is already used

%w[ab cd].each { _1.each_char { p _1 } }
# SyntaxError: numbered parameter is already used in outer block

_1 = "deneme"
# SyntaxError: _1 is reserved for numbered parameters
  • Açık parametresi olan bir blokta it kullanılamaz (aynı adda yerel değişken yoksa).
  • Numaralı parametreler açık parametrelerle de birlikte kullanılamaz.
  • _1 ile it aynı blokta karıştırılamaz.
  • Numaralı parametre kullanan bloklar iç içe yazılamaz; it kullanan bloklar yazılabilir.
  • _1 gibi adlar yerel değişken ya da metot parametresi olarak kullanılamaz. Ruby 3.0 NEWS dosyasına göre numaralı parametreye atama yapmak bu sürümden beri uyarı değil SyntaxError.

arity ve parameters üzerindeki etkisi

Adsız parametreler bloğun imzasını da belirler. Belgelere göre it kullanan bloklar tek parametreli sayılır; numaralı parametrelerde ise kullanılan en büyük numara parametre sayısını verir. Proc'ta parametreler isteğe bağlı (:opt), lambdada zorunlu (:req) görünür. Proc ile lambda arasındaki diğer farklar için Proc ve lambda yazısına bakabilirsiniz.

ruby
p proc { it * 2 }.arity            # çıktı: 1
p proc { it * 2 }.parameters       # çıktı: [[:opt]]
p lambda { it * 2 }.parameters     # çıktı: [[:req]]
p proc { _1 + _2 }.arity           # çıktı: 2
p lambda { _1 + _2 }.parameters    # çıktı: [[:req, :_1], [:req, :_2]]

Ruby 4.0: Binding#implicit_parameters

Ruby 4.0 NEWS dosyasına göre Binding#local_variables artık numaralı parametreleri listelemiyor ve local_variable_get gibi metotlar numaralı parametreleri reddediyor. Bunların yerine it ve numaralı parametrelere erişmek için Binding#implicit_parameters, Binding#implicit_parameter_get ve Binding#implicit_parameter_defined? eklendi. Bu metotlar daha çok hata ayıklama ve araç geliştirme için işe yarar.

ruby
[7].each do
  p binding.implicit_parameters          # çıktı: [:it]
  p binding.implicit_parameter_get(:it)  # çıktı: 7
  it
end

[[1, 2]].each do
  _2
  p binding.implicit_parameters # çıktı: [:_1, :_2]
end

Hangi yazım hangi sürümde geldi?

Hangi yazım hangi sürümde geldi? |a, b|, |x; y|, _1 ... _9, _1 = ...
YazımNe yaparKaynakta geçen sürüm
|a, b|Açık blok parametreleriTemel dil özelliği
|x; y|Blok-yerel değişkenTemel dil özelliği
_1 ... _9Numaralı parametrelerRuby 2.7 NEWS
_1 = ...Atama SyntaxError olurRuby 3.0 NEWS
itTek blok parametresiRuby 3.4 NEWS (3.3 uyarı verdi)
binding.implicit_parametersit ve _1 için Binding erişimiRuby 4.0 NEWS

Hangisini ne zaman kullanmalı?

Kısa, tek satırlık ve tek parametreli bloklarda it okunabilirliği bozmadan kodu kısaltır: dosyalar.map { it.strip }. İki parametreli kısa bloklarda _1 ve _2 işe yarar, ama parametreler anlamlı bir şeyi temsil ediyorsa (|ad, adet|) açık ad vermek kodu daha anlaşılır kılar. Çok satırlı bloklarda, iç içe bloklarda ve parçalama gereken durumlarda açık parametre tercih edin. &:upcase gibi sembol kısayolu ise yalnızca tek bir metot çağıracağınız durumlarda en kısa seçenektir.

Aynı işi dört farklı yazımla yapan aşağıdaki örnek, seçenekleri yan yana görmenizi sağlar. Dördü de aynı sonucu verir; fark yalnızca okunabilirlik ve esneklikte. Sembol kısayolu yalnızca argümansız tek bir metot çağrısında çalışır. Bloğun içinde birden fazla işlem yapmanız gerektiğinde it ya da açık parametre gerekir. Hash gibi çiftlerle çalışırken ise açık parametreler, değerlerin ne anlama geldiğini kodun içinde belgelemiş olur.

ruby
satirlar = ["  elma ", "armut  ", " kiraz"]
p satirlar.map { |s| s.strip } # çıktı: ["elma", "armut", "kiraz"]
p satirlar.map { it.strip }    # çıktı: ["elma", "armut", "kiraz"]
p satirlar.map { _1.strip }    # çıktı: ["elma", "armut", "kiraz"]
p satirlar.map(&:strip)        # çıktı: ["elma", "armut", "kiraz"]

p satirlar.map { it.strip.capitalize } # çıktı: ["Elma", "Armut", "Kiraz"]
fiyat = { elma: 30, armut: 45 }
p fiyat.map { |urun, tl| "#{urun}: #{tl} TL" } # çıktı: ["elma: 30 TL", "armut: 45 TL"]

Metin işleme metotlarının ayrıntıları için Ruby String metotları yazısına bakabilirsiniz.

Sık Sorulan Sorular

Ruby 3.3 veya daha eski bir sürümde it kullanabilir miyim?

NEWS dosyalarına göre it blok parametresi olarak Ruby 3.4 ile geldi; 3.3 bu kullanım için yalnızca uyarı veriyordu. Eski sürümleri destekleyen kodda _1 (2.7 ve sonrası) ya da açık parametre kullanın.

it bir anahtar kelime mi?

Hayır. Belgeler onu "soft keyword" olarak tanımlar; it adlı bir metot ya da değişken tanımlayabilirsiniz. Ancak aynı blokta değişken ve parametre anlamını birlikte kullanmak kafa karıştırıcıdır.

Neden _1 ile _2 aynı blokta kullanılabiliyor da it ile _1 kullanılamıyor?

_1 ve _2 aynı sistemin parçalarıdır. it ise ayrı bir mekanizmadır ve Ruby ikisinin karıştırılmasına izin vermez; denemeniz SyntaxError ile sonuçlanır.

Lambda içinde it kullanabilir miyim?

Evet. lambda { it * 2 } zorunlu tek parametreli bir lambda üretir; parameters çıktısı [[:req]] 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 · Blok ve yield · Proc ve lambda farkı · Enumerator ve Lazy · Ruby 4.0 yenilikleri