Symbole w Ruby 3

Posted by wijet
on Tuesday, August 07
Symbol jest identyfikatorem który odpowiada łańcuchowi znaków, możemy go traktować jako “lżejszą” odmianę stringa. Symbole możemy definiować na kilka sposobów.
:foo
:'foo'
:"foo"
"foo".to_sym

Symbol posiada zarówno reprezentacje liczbową jak i znakową. Dla nas bardziej znacząca jest reprezentacja znakowa. Faktycznie symbole możemy traktować jako stringi, ale stringi niemodyfikowalne tzn. nie mogą występować po lewej stronie operatora przypisania. Wiec jeśli nie potrzebujemy modyfikować napisu ani używać metod z klasy String, możemy skorzystać z symboli. Kolejnym dobrym zastosowaniem jest użycie symboli w charakterze stałych np: jako przełącznik, tak jak poniżej.

def read_file(file_name,user_mode)
  case user_mode
    when :nobody
      #....
    when :user
      #....
    when :admin
     #....
  end
end
read_file("config.txt",:user)

Bardzo ważna właściwością symboli jest to, że podczas działania programu takie same symbole są zawsze odwołaniem do jednego obiektu w pamięci, który jest tworzony tylko raz. Przeanalizujmy wyniki działania poniższego skryptu, który wyświetla id utworzonych obiektów.

puts "foo".object_id
puts "foo".object_id
puts :foo.object_id
puts :foo.object_id

Wyniki:

-608242448
-608245628
335378
335378

Jak widać “foo” i “foo” to tak naprawdę dwa różne obiekty (zajmują różne miejsca w pamięci) natomiast w przypadku symboli :foo i :foo widzimy że id jest takie same, a wiec stosując symbole oszczędzamy pamięć. Dlatego świetnym zastosowaniem dla symboli jest użycie ich jako kluczy w haszu.
foo = {:boo => 12,:bar => "ble" }

  1. odwołanie
    foo[:bar]

W tym przypadku zysk w postaci zaoszczędzonej pamięci będzie znikomy, ale warto zauważyć ze jeśli mielibyśmy np. tablice użytkowników typu

users = [{:login => "abc",:pass => "qaz",:email => :email => "abc@domain.pl"},
              {:login => "qwe",:pass => "rty",:email => :email => "eee@domain.pl"}
             ]

zawierająca 100 użytkowników i zamiast symboli używali stringów jako kluczy. Zamiast 3 obiektów (kluczy) mielibyśmy 300 obiektów, które zwykle nie są nam do niczego potrzebne i tylko pożerają pamięć.

Jak już pisałem symbole posiadają także reprezentacje liczbową którą możemy otrzymać wywołując metodę to_i.
Jest ona używana podczas porównywania symboli, tzn. porównywana jest reprezentacja liczbowe czyli liczby. Jeżeli dwa symbole maja taką sama reprezentacje liczbowa to znaczy że są to te same symbole. W przypadku stringów sytuacja wygląda inaczej porównując dwa stringi na pewny poziomie abstrakcji tak naprawdę dochodzi do porównywania znak po znaku, co jest bardziej czasochłonne niż porównywanie dwóch liczb.

Symbole są powszechnie używane do przekazywania nazw metod i zmiennych, np przy tworzeniu setterów i getterów. W klasie poniżej tworzony jest getter dla zmiennej @foo aby można było odczytać ją z poza obiektu.

class Boo
  attr_reader :foo
end

Metoda attr_reader zadziała tak samo jeśli przekażemy nazwę zmiennej jako string, wynika to z jednak z jej implementacji a nie z jakiejś “magi” symboli.
W następnym przykładzie używamy metody send z klasy Object, uruchamia ona metodę przekazaną jej jako symbol.

obj.send(:foo)

W obu przykładach ponownie pojawia się pytanie, po co symbole? Gdybyśmy przekazali nazwy atrybutów, metod jako stringi wszystko by działało, w tych przypadkach użycie symboli (oprócz tego że jest bardziej optymalne) jest bardziej naturalne. Nie obchodzi nas tak naprawdę nazwa jako sekwencja znaków,nie interesuje nas treść tylko to co ona symbolizuje(identyfikuje).

Comments

Leave a response

  1. V.August 07, 2007 @ 11:10 PM

    Więc, mówiąc wprost, symbole to stałe? Ruby: @bar = :foo PHP: const FOO = 1; // … $this -> bar = self::FOO; Co do współpracy symbolów i identyfikatorów, czy nie mają przypadkiem identycznej składni?

  2. wijetAugust 07, 2007 @ 11:47 PM

    Więc, mówiąc wprost, symbole to stałe? Symbole można traktować jako stałe, ale nie są to typowe stałe Ruby. bq. Co do współpracy symbolów i identyfikatorów, czy nie mają przypadkiem identycznej składni W jakim sensie identycznej składni? tam gdzie metody przyjmują argument jako symbol nie możemy po prostu przekazać identyfikatora.

  3. onlineDecember 22, 2009 @ 07:23 PM

    Dzieki za ciekawe informacje

Comment