2011-12-20 14 views
33

Rozważmy następujący kod:Czy ciągi znaków w Ruby są zmienne?

$ irb 
> s = "asd" 
> s.object_id # prints 2171223360 
> s[0] = ?z  # s is now "zsd" 
> s.object_id # prints 2171223360 (same as before) 
> s += "hello" # s is now "zsdhello" 
> s.object_id # prints 2171224560 (now it's different) 

Wygląda poszczególnych znaków można zmienić w/o stworzenie nowego łańcucha. Jednak dodanie do łańcucha najwyraźniej tworzy nowy ciąg.

Czy łańcuchy w Ruby są zmienne?

+2

Tak, i odpowiada za pomocą banalnego wyszukiwania. http://stackoverflow.com/questions/2608493/why-did-matz-choose-to-make-strings-mutable-by-default-in-ruby –

+0

@DaveNewton: Czy to nie wspaniale, jak łatwo jest znaleźć dups na SO, jak możesz prawie liczyć na temat SI wymyślić pierwszy w google? –

+4

'+' jest konkatenacją i zwróci nowy ciąg. '<<' jest Dopisywanie i dopisze do danego obiektu typu string (nie tworzy nowego). – Chad

Odpowiedz

37

Tak, łańcuchy w Ruby, w przeciwieństwie do Pythona, są zmienne.

s += "hello" jest nie dołączanie "hello" do s - zupełnie nowy obiekt ciąg zostanie utworzona. Aby dołączyć do łańcucha „w miejscu”, użyj <<, jak w:

s = "hello" 
s << " world" 
s # hello world 
+3

Czy ma sens myślenie o 'a + = b' jako' a = a + b' w Ruby? To by wyjaśniało, dlaczego 's + =" hello "' tworzy nowy ciąg. – emlai

+1

@tuple_cat Tak, w ten sposób zaimplementowano '+ =', dlatego redefiniowanie '+' daje przedefiniowane '+ ='. – YoTengoUnLCD

8

Dołączanie w Ruby String nie jest +=, to <<

Więc jeśli zmienisz += do << zapytanie zostanie skierowane przez siebie

+3

+1. Jak wyjaśniono na http://www.rubyfleebie.com/appending-to-a-string/, "' + = 'utworzy nową instancję String i przypisze ją do twojego lewego obiektu." " 'doda nowy ciąg bezpośrednio do twojego już istniejącego obiektu." – ruakh

11
ruby-1.9.3-p0 :026 > s="foo" 
=> "foo" 
ruby-1.9.3-p0 :027 > s.object_id 
=> 70120944881780 
ruby-1.9.3-p0 :028 > s<<"bar" 
=> "foobar" 
ruby-1.9.3-p0 :029 > s.object_id 
=> 70120944881780 
ruby-1.9.3-p0 :031 > s+="xxx" 
=> "foobarxxx" 
ruby-1.9.3-p0 :032 > s.object_id 
=> 70120961479860 

tak, Struny są zmienne, ale += operator tworzy nowy ciąg. << utrzymuje stary

6

Struny w Ruby są zmienne, ale można go zmienić z zamarzaniem.

irb(main):001:0> s = "foo".freeze 
=> "foo" 
irb(main):002:0> s << "bar" 
RuntimeError: can't modify frozen String 
0

Z tego, co mogę zrobić z this pull request, stanie się możliwe w Ruby 3.0, aby dodać komentarz „magiczne”, które uczynią wszystko ciąg niezmienne zamiast zmienny.

Ponieważ wydaje się, że musisz jawnie dodać ten komentarz, wydaje się, że odpowiedź brzmi "czy zmienna łańcuchowa jest domyślnie?" nadal będzie "tak", ale rodzaj warunkowego "tak" - zależy od tego, czy wpisałeś magiczny komentarz do swojego skryptu, czy nie.

EDIT

I wskazywano na to, że ostatecznie bug/issue on Ruby-Lang.org stwierdza, że ​​niektóre rodzaj ciągów w Ruby 3.0 będzie w rzeczywistości być niezmienna domyślnie.

1

Struny ruby ​​są zmienne. Ale musisz użyć < < do łączenia zamiast +.
W rzeczywistości łączenie ciągiem znaków z
+ operator (niezmienny), ponieważ tworzy nowy obiekt ciągu.
< < operator (zmienne) ponieważ zmienia się w tym samym obiekcie.