Ruby'de bir değişkenin türünü, adının ilk karakteri belirler: küçük harf veya alt çizgiyle başlayan adlar yerel değişken, @ ile başlayanlar örnek değişkeni, @@ ile başlayanlar sınıf değişkeni, $ ile başlayanlar global değişken, büyük harfle başlayanlar ise sabit olur. Değişken tanımlamak için var veya let gibi bir anahtar kelime yoktur; ilk atama değişkeni oluşturur.

Bu yazıda her değişken türünün kapsamını, hiç atanmamışken ne döndürdüğünü ve en sık karşılaşılan tuzakları resmî Assignment belgesi temelinde, Ruby 4.0 ile çalıştırılmış örneklerle anlatıyoruz. Serinin genel planı için Ruby öğrenme rehberi sayfasına bakabilirsiniz.

Değişken türlerine genel bakış

Değişken türlerine genel bakış: Yerel değişken, Örnek değişkeni, Sınıf değişkeni, Global değişken
TürÖnekÖrnekNerede görünürAtanmamışsa
Yerel değişkenküçük harf veya _toplamTanımlandığı metot, blok veya dosyaMetot çağrısı sanılır, NameError
Örnek değişkeni@@degerAynı nesnenin tüm metotlarınil
Sınıf değişkeni@@@@adetSınıf, alt sınıfları ve örnekleriNameError
Global değişken$$istek_sayisiProgramın her yerinil
SabitBüyük harfMAKS_DENEMETanımlandığı sınıf veya modül ve iç içe kapsamlarNameError

Yerel değişkenler

Yerel değişken adı küçük bir ASCII harfle başlar; harf, rakam ve alt çizgi içerebilir. Belgeler, sekizinci biti dolu karakterlere de izin verildiğini belirtir; bu yüzden UTF-8 dosyalarda şehir gibi Türkçe harfli adlar çalışır. Yine de takım çalışmasında herkesin klavyesinde kolayca yazılabilen ASCII adlar tercih edilir. Belgelerdeki örnekler de kelimeleri alt çizgiyle ayıran big_calculation biçimini kullanır.

Bir blok (do ... end veya süslü parantez) yeni bir kapsam açar. Bloğun içinde oluşturulan değişken dışarı sızmaz, ancak dışarıda tanımlı bir değişken bloğun içinden görülür ve değiştirilebilir:

ruby
toplam = 0
[10, 20, 30].each do |sayi|
  toplam += sayi
  son = sayi
end

p toplam           # çıktı: 60
p defined?(son)    # çıktı: nil

şehir = "İzmir"
p şehir            # çıktı: "İzmir"

Önemli bir ayrıntı: yerel değişken, atama satırı çalıştığında değil, ayrıştırıcı (parser) atamayı gördüğünde oluşur. Aşağıdaki atama hiç çalışmaz, ama a yine de yerel değişken olarak kaydedilir ve değeri nil olur:

ruby
a = 5 if false
p local_variables   # çıktı: [:a]
p a                 # çıktı: nil

Yerel değişken mi, metot mu?

Ruby'de parantezsiz metot çağrısı ile yerel değişken aynı görünür. Ayrıştırıcı bir ada daha önce atama yapılmadığını görürse onu metot çağrısı sayar. Modifier if ile yazılan şu satır bu yüzden hata verir: önce soldaki deger okunur ve henüz atama görülmediği için metot sanılır, ardından sağdaki atama çalışır, sonra var olmayan metot çağrılmaya çalışılır.

ruby
begin
  p deger if deger = 0.zero?
rescue NameError => e
  puts e.class      # çıktı: NameError
  puts e.message    # çıktı: undefined local variable or method 'deger' for main
end

Çözüm, atamayı ayrı bir satıra almak veya uzun if ... end biçimini kullanmaktır. Aynı ada sahip bir metodu yerel değişken varken çağırmak isterseniz self.ad yazın veya boş parantez ekleyin: ad().

Örnek değişkenleri (@)

@ ile başlayan örnek değişkenleri, bir nesnenin durumunu tutar. Aynı nesnenin bütün metotları bu değişkenleri paylaşır, ama her nesnenin kendi kopyası vardır. Hiç atanmamış bir örnek değişkeni okunduğunda hata vermez, nil döner. Sınıfların ayrıntıları Ruby class ve nesneler yazısında.

ruby
class Sayac
  def initialize(baslangic)
    @deger = baslangic
  end

  def artir
    @deger += 1
  end

  def aciklama
    @aciklama
  end
end

s1 = Sayac.new(0)
s2 = Sayac.new(100)
s1.artir
s1.artir
p s1.artir               # çıktı: 3
p s2.artir               # çıktı: 101
p s1.aciklama            # çıktı: nil
p s1.instance_variables  # çıktı: [:@deger]

Örnek değişkenine dışarıdan erişmek için genellikle attr_accessor kullanılır; bu, okuma ve fiyat= biçiminde yazma metotları üretir. Burada sık yapılan bir hata vardır: metot içinde alıcı belirtmeden fiyat = 50 yazarsanız Ruby bunu yazma metodu değil, yeni bir yerel değişken sayar. Yazma metodunu çağırmak için self. öneki şarttır:

ruby
class Urun
  attr_accessor :fiyat

  def indirim_yanlis
    fiyat = 50          # yalnızca yerel bir değişken oluşturur
  end

  def indirim_dogru
    self.fiyat = 50     # fiyat= metodunu çağırır
  end
end

u = Urun.new
u.fiyat = 100
u.indirim_yanlis
p u.fiyat   # çıktı: 100
u.indirim_dogru
p u.fiyat   # çıktı: 50

Sınıf değişkenleri (@@)

@@ ile başlayan sınıf değişkenleri bir sınıf, onun alt sınıfları ve tüm örnekleri arasında tek bir değer olarak paylaşılır. Alt sınıf değeri değiştirdiğinde üst sınıf da yeni değeri görür. Atanmamış bir sınıf değişkenini okumak, örnek değişkenlerinden farklı olarak NameError fırlatır.

ruby
class Arac
  @@adet = 0

  def initialize
    @@adet += 1
  end

  def self.adet
    @@adet
  end
end

class Kamyon < Arac
end

Arac.new
Kamyon.new
Kamyon.new
p Arac.adet     # çıktı: 3
p Kamyon.adet   # çıktı: 3

class Bos
  def self.oku
    @@yok
  end
end

begin
  Bos.oku
rescue NameError => e
  puts e.message  # çıktı: uninitialized class variable @@yok in Bos
end

Belgeler bir karışıklığa özellikle dikkat çeker: sınıflar da birer nesne olduğu için sınıf gövdesinde yazılan @ortam gibi bir değişken, sınıf değişkeni değil sınıf nesnesinin örnek değişkenidir. Bu değişken alt sınıflarla paylaşılmaz:

ruby
class Ayar
  @ortam = "üretim"

  class << self
    attr_reader :ortam
  end
end

class AltAyar < Ayar
end

p Ayar.ortam      # çıktı: "üretim"
p AltAyar.ortam   # çıktı: nil

Global değişkenler ($)

Global değişkenler ($): Son yükseltilen istisna nesnesi veya nil, Son başarılı eşleşmenin MatchData nesnesi, $1, $2, ..., $stdout, $stderr

$ ile başlayan değişkenlere programın her yerinden erişilir; atanmamışsa değerleri nil olur. Her yerden değiştirilebildikleri için hangi kodun değeri değiştirdiğini izlemek zorlaşır; bu yüzden kendi verileriniz için genellikle sabit, örnek değişkeni veya metot parametresi daha anlaşılır bir seçimdir.

ruby
$istek_sayisi = 0

def istek_al
  $istek_sayisi += 1
end

3.times { istek_al }
p $istek_sayisi   # çıktı: 3
p $tanimsiz       # çıktı: nil

Ruby'nin önceden tanımladığı global değişkenler ise günlük kodda sık görülür. Pre-Defined Global Variables belgesi bunları gruplar halinde listeler: son eşleşmenin bilgisi ($~, $1, $2), son yakalanan istisna ($!), standart akışlar ($stdout, $stderr), program adı ($0) gibi.

ruby
"Tarih: 2026-11-07" =~ /(\d+)-(\d+)-(\d+)/
p $~[0]               # çıktı: "2026-11-07"
p $1                  # çıktı: "2026"
p $3                  # çıktı: "07"
p $stdout == STDOUT   # çıktı: true
DeğişkenİçerdiğiSalt okunur mu
$!Son yükseltilen istisna nesnesi veya nilEvet
$~Son başarılı eşleşmenin MatchData nesnesiHayır
$1, $2, ...Son eşleşmenin yakalama gruplarıEvet
$stdout, $stderrStandart çıktı ve hata akışıHayır
$0Çalışan programın adıHayır
$LOAD_PATHrequire için aranan klasörlerEvet

Sabitler

Büyük harfle başlayan her ad bir sabittir; sınıf ve modül adları da birer sabittir. Ruby'de sabitler aslında yeniden atanabilir, ancak yorumlayıcı bunu bir uyarıyla bildirir. Program çalışmaya devam eder ve sabit yeni değeri alır:

ruby
MAKS_DENEME = 3
MAKS_DENEME = 5
p MAKS_DENEME     # çıktı: 5
bash
ornek.rb:2: warning: already initialized constant MAKS_DENEME
ornek.rb:1: warning: previous definition of MAKS_DENEME was here
5

Uyarı yalnızca sabitin başka bir nesneye bağlanmasında çıkar. Sabitin gösterdiği nesnenin içeriğini değiştirmek hiçbir uyarı üretmez. İçeriğin değişmesini engellemek için nesneyi freeze ile dondurmanız gerekir; ayrıntılar Ruby frozen string ve freeze yazısında.

ruby
RENKLER = ["kırmızı", "mavi"]
RENKLER << "yeşil"
p RENKLER          # çıktı: ["kırmızı", "mavi", "yeşil"]

SABIT_LISTE = ["a", "b"].freeze
begin
  SABIT_LISTE << "c"
rescue FrozenError => e
  puts e.message   # çıktı: can't modify frozen Array: ["a", "b"]
end

begin
  OLMAYAN_SABIT
rescue NameError => e
  puts e.message   # çıktı: uninitialized constant OLMAYAN_SABIT
end

Bir metot gövdesinin içinde sabite değer atamaya çalışırsanız kod hiç çalışmaz; Ruby dosyayı ayrıştırırken SyntaxError verir ve mesajda dynamic constant assignment ifadesi geçer. Sabitler sınıf veya modül gövdesinde ya da dosyanın en üst seviyesinde tanımlanmalıdır.

Sabitler tanımlandıkları sınıf veya modülün ad alanına aittir. İç içe yazılmış bir modülün içinden dıştaki sabitler görülür; aynı adlı üst seviye sabite ulaşmak için başına :: konur. Ruby'nin kendi sabitleri de aynı kurala uyar; RUBY_VERSION çalışan sürümü verir:

ruby
LIMIT = 10

module Ayarlar
  LIMIT = 50

  def self.goster
    [LIMIT, ::LIMIT]
  end
end

p Ayarlar.goster   # çıktı: [50, 10]
p Ayarlar::LIMIT   # çıktı: 50
p RUBY_VERSION     # çıktı: "4.0.9"

Atama biçimleri

Bir atama ifadesinin sonucu her zaman atanan değerdir. Ruby birkaç kısa atama biçimi sunar: a += 2, a = a + 2 ile aynıdır ve +, -, *, /, %, **, &, |, ^, <<, >> için kullanılabilir. ||= değişken nil veya false ise atama yapar; &&= ise tam tersine, değer bu ikisinden biri değilse atar. Çoklu atama ile birden fazla değişkene tek satırda değer verilir, iki değişkenin değeri yer değiştirilir ve * ile kalan elemanlar toplanır.

ruby
a, b = 1, 2
a, b = b, a
p [a, b]          # çıktı: [2, 1]

ilk, *kalan = [10, 20, 30, 40]
p ilk             # çıktı: 10
p kalan           # çıktı: [20, 30, 40]

x, (y, z) = 1, [2, 3]
p [x, y, z]       # çıktı: [1, 2, 3]

liste = 1, 2, 3
p liste           # çıktı: [1, 2, 3]

ayar = nil
ayar ||= "varsayılan"
ayar ||= "başka"
p ayar            # çıktı: "varsayılan"

sayac = 5
sayac += 2
p sayac           # çıktı: 7

Sol tarafta sağdakinden az değişken varsa fazla değerler yok sayılır; yıldızlı değişken (*kalan) sol tarafın herhangi bir yerinde olabilir ama tek bir atamada yalnızca bir tane kullanılabilir. Belgeler a ||= 0 ifadesinin a = a || 0 yerine a || a = 0 gibi davrandığını not eder: değer zaten doluysa hiçbir atama yapılmaz.

Sık yapılan hatalar

Sık yapılan hatalar: Yazma metodunu self. olmadan çağırmak, Modifier if içinde atama yapmak, Sabitin değişmez olduğunu sanmak, Sınıf değişkenini alt sınıftan bağımsız sanmak
  • Yazma metodunu self. olmadan çağırmak: metot içinde fiyat = 50 yerel değişken oluşturur, nesnenin durumunu değiştirmez.
  • Modifier if içinde atama yapmak: p a if a = deger biçimi, ayrıştırma sırası yüzünden NameError verir.
  • Sabitin değişmez olduğunu sanmak: yeniden atama yalnızca uyarı verir, içerik değişikliği ise hiç uyarı vermez. Gerçek koruma için freeze kullanın.
  • Sınıf değişkenini alt sınıftan bağımsız sanmak: @@ değişkeni tüm hiyerarşide tek bir değerdir. Sınıf başına ayrı değer istiyorsanız sınıf düzeyinde örnek değişkeni kullanın.
  • Blok içinde tanımlanan değişkeni dışarıda kullanmaya çalışmak: blok yeni kapsam açar. Değeri dışarıda kullanacaksanız değişkeni bloktan önce tanımlayın. Döngülerdeki kapsam farkı için Ruby döngüler yazısına bakın.

Sık Sorulan Sorular

Ruby'de değişken tanımlamak için anahtar kelime var mı?

Hayır. Bir ada ilk kez değer atamak, o kapsamda yerel değişkeni oluşturur. Türü de belirtmezsiniz; değişken herhangi bir nesneyi gösterebilir ve sonradan başka türde bir nesneye bağlanabilir.

Atanmamış bir örnek değişkeni neden hata vermiyor?

Belgelere göre atanmamış örnek değişkenleri ve global değişkenler nil değerine sahiptir. Sınıf değişkenleri ve sabitler için durum farklıdır; ikisi de atanmamışken okunduğunda NameError fırlatır.

Sabitin yeniden atanmasını tamamen engelleyebilir miyim?

Yeniden atama sözdizimi olarak engellenmez, yalnızca uyarı üretir. Pratikte sabitleri bir kez tanımlayıp gösterdikleri nesneyi freeze ile dondurmak, kazara değişikliklere karşı en etkili yoldur.

Değişken adlarında Türkçe karakter kullanabilir miyim?

Kaynak dosya UTF-8 olduğunda kullanabilirsiniz; belgeler sekizinci biti dolu karakterlere izin verir. Ancak büyük harfle başlayan bir ad sabit sayılacağı için, adı küçük harfle başlatmanız gerekir. Kodlama konusunun ayrıntıları Ruby encoding ve Türkçe karakter yazısında.

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 veri tipleri ve literaller · Ruby class ve nesneler · Ruby frozen string ve freeze · Ruby blok ve yield