Reference

Jak przekazac do funkcji reference do obiektu? Wiem ze kazdy element w rubym jest obiektem, ale niewiele mi to pomaga bo nie wiem jak to zastosowac.
Potrzebna mi jest funkcja np:
def test(&pVar)
pVar = ‘dasasd’
return ‘ok’
end

b = 1
a= test(b)

i b = ‘dasasd’ a b = ‘ok’

jak takie cos zrobic?

Generalnie w Rubim działamy na referencji, ale gdy przekazujesz do swojej funkcji wartość bo, robisz w ten sposób jej kopię. Zatem podmiana tej wartości nie powoduje zmiany oryginalnego obiektu. Można uzyskać żądany przez Ciebie efekt, aczkolwiek nie jest to najładniejszy sposób :-). Moja propozycja na szybko:

[code]def fun1(b)
b = “dsadsa”
return “ok”
end

b = 1
a = fun1(b)
puts “a = #{a}, b = #{b}” #=> a = ok, b = 1

def fun2(b, binding)
eval(%{
b = “dsadsa”
}, binding)
return “ok”
end

b = 1
a = fun2(b, binding)
puts “a = #{a}, b = #{b}” #=> a = ok, b = dsadsa

b = 1
a = fun2(b, nil)
puts “a = #{a}, b = #{b}” #=> a = ok, b = 1[/code]
Odsyłam do manuala: ri Kernel#eval oraz ri Kernel#binding

No fakt, nie wyglada to za ladnie :). Dzieki wymysle jakis inny sposob aby rozwiazac swoj problem.

Możesz także opakować swoją klasę jakąś klasą wrapperem i w niej trzymać referencję, która zostanie podmieniona.

[code]class Wrapper
attr_accessor :value

def initialize(value)
	@value = value
end

end

def fun3(b)
b.value = “dsadsa”
return “ok”
end

b = Wrapper.new(1)
a = fun3(b)
puts “a = #{a}, b = #{b.value}” #=> ok, dsadsa[/code]
Generalnie o czymś takim jak przekazanie zmiennej przez referencje zapomnij :-). Zmieniaj po prostu stan przekazywanych obiektów.

Ja wolę myśleć o tym jak o wskaźnikach. Jeśli przekazuję coś do funkcji, to przekazuję wskaźnik na ten obiekt, jeśli zmienię wskaźnik w środku funkcji, to logicznym, że nie zmienię go na zewnątrz, jeśli jednak zmienię obiekt, na który wskaźnik wskazuje to wskaźnik z zewnątrz będzie wskazywał na ten obiekt.

rupert@laptop:~$ irb irb(main):001:0> a = "aba" => "aba" irb(main):002:0> b = "abba" => "abba" irb(main):003:0> def m(o) irb(main):004:1> o = "n" irb(main):005:1> end => nil irb(main):006:0> m(a) => "n" irb(main):007:0> a => "aba" irb(main):008:0> def m2(o) irb(main):009:1> o.capitalize! irb(main):010:1> end => nil irb(main):011:0> m2(a) => "Aba" irb(main):012:0> a => "Aba"

Dodoba mi sie sposob paneq`a.

Mozna wtedy sobie rozszerztyc powiedzmy klasy String i FixNum o metde change_value! i wtedy po wywolaniu:

a = 5

def m(o)
a.change_value!(6)
end

m(a)

a bedzie wynosic 6.

No ale lepiej projektowac kod w ten sposob aby unikac takich sytuacji.

Ja wolę myśleć o tym jak o wskaźnikach. Jeśli przekazuję coś do funkcji, to przekazuję wskaźnik na ten obiekt, jeśli zmienię wskaźnik w środku funkcji, to logicznym, że nie zmienię go na zewnątrz, jeśli jednak zmienię obiekt, na który wskaźnik wskazuje to wskaźnik z zewnątrz będzie wskazywał na ten obiekt.[/quote]
Wydaje mi się, że to jest dokładnie to samo :). Podstaw za ‘wskaźnik’ słowo ‘referencja’ i zobacz, że sens jest zachowany.

[quote=sandmann]Mozna wtedy sobie rozszerztyc powiedzmy klasy String i FixNum o metde change_value! i wtedy po wywolaniu:

a = 5

def m(o)
a.change_value!(6)
end

m(a)

a bedzie wynosic 6.[/quote]
A próbowałeś tak zrobić? Bo dla klas, które podałeś jest to niewykonalne. Dlaczego? Ponieważ dajmy na to w klasie String nie da się podmienić “samego siebie” (self) na inny obiekt. Implementacja musiałaby wyglądać mniej więcej tak:

class String def change_value(str) self = str #nie przejdzie end end
a to niestety nie zadziała. Mało tego, obiekty liczbowe (FixNum) są niemutowalne, tzn raz utworzony obiekt nie zmienia swojego stanu i Ruby nie udostępnia metod, które je zmieniają.

Obiekty String, Array, Hash i Set mają metodę replace, która pomienia ich zawartość na nową. Niestety nie da się tak postąpić z liczbami.