2012-02-03 10 views
5

ze strunami można to zrobić:Generic sposób wymienić przedmiot w jego własnej metody

a = "hello" 
a.upcase! 
p a #=> "HELLO" 

Ale jak chciałbym napisać własną metodę takiego?

Coś podobnego (choć oczywiście nie działa):

class MyClass 
    def positify! 
    self = [0, self].max 
    end 
end 

Wiem, że istnieje kilka sztuczek można użyć na String ale co jeśli ja staram się zrobić coś takiego dla obiektu?

Odpowiedz

4

Cóż, metoda upcase! nie zmienia tożsamości obiektu, zmienia jedynie jego wewnętrzną strukturę (s.object_id == s.upcase!.object_id).

Z drugiej strony, numery są niezmienne obiekty i dlatego nie można zmieniać ich wartości, bez zmiany ich tożsamości. AFAIK, nie ma możliwości, aby obiekt samoczynnie zmienił swoją tożsamość, ale oczywiście możesz zaimplementować metodę, która zmienia właściwości obiektu - i jest to analogia tego, co się dzieje! robi dla ciągów.

2

Przyporządkowanie lub powiązanie zmiennych lokalnych (przy użyciu operatora =) jest wbudowane w język podstawowy i nie ma możliwości jego przesłonięcia lub dostosowania. Możesz uruchomić preprocesor na swoim kodzie Ruby, który mógłby przekonwertować twoją własną, niestandardową składnię na poprawną Ruby. Można również przekazać do niestandardowej metody, która może dynamicznie redefiniować zmienne. Nie przyniosłoby to efektu, którego szukasz.

Zrozum, że self = nigdy nie będzie działać, ponieważ kiedy mówisz a = "string"; a = "another string", nie modyfikujesz żadnych obiektów; ponownie przypisujesz zmienną lokalną do innego obiektu. Wewnątrz niestandardowej metody znajdujesz się w innym zakresie, a wszelkie zmienne lokalne, które zwiążesz, będą istnieć tylko w tym zakresie: w tym zakresie:; nie będzie to miało wpływu na zakres, z którego nazwałaś metodę.

2

Nie można zmienić siebie, aby wskazywać na coś innego niż jego aktualnego obiektu. Można wprowadzać zmiany w zmiennych instancji, na przykład w ciągu znaków, który zmienia znaki bazowe na wielkie litery.

Jak wskazano w tej odpowiedzi: Ruby and modifying self for a Float instance

Jest trik tu wspomnieć, że jest to praca dokoła, który jest napisać ci klasy jako owinięcia wokół innego obiektu. Wtedy twoja klasa wrapperów może dowolnie zastąpić zawinięty obiekt. Waham się jednak, że to dobry pomysł.

7

Wiele klas jest niezmiennych (np. Numeric, Symbol, ...), więc nie ma metody pozwalającej na zmianę ich wartości.

Z drugiej strony, każdy Object może mieć zmienne instancji, a te mogą być modyfikowane.

Istnieje prosty sposób przekazania zachowania do znanego obiektu (na przykład 42) i późniejszego zmienienia na inny obiekt przy użyciu SimpleDelegator.W poniższym przykładzie quacks_like_an_int zachowuje się jak Integer:

require 'delegate' 
quacks_like_an_int = SimpleDelegator.new(42) 
quacks_like_an_int.round(-1) # => 40 
quacks_like_an_int.__setobj__(666) 
quacks_like_an_int.round(-1) # => 670 

Można go używać do projektowania klasę też, na przykład:

require 'delegate' 
class MutableInteger < SimpleDelegator 
    def plus_plus! 
    __setobj__(self + 1) 
    self 
    end 

    def positify! 
    __setobj__(0) if self < 0 
    self 
    end 
end 

i = MutableInteger.new(-42) 
i.plus_plus! # => -41 
i.positify! # => 0 
Powiązane problemy