Pracuję przez Ruby Koans.
test_the_shovel_operator_modifies_the_original_string
Koan w about_strings.rb zawiera następującą uwagę:
Programiści Ruby mają tendencję do faworyzowania operatora łopaty (<<) zamiast operatora plus równa się (+ =) podczas tworzenia łańcuchów. Czemu?
Domyślam się, że wiąże się to z prędkością, ale nie rozumiem działania pod maską, które spowodowałoby, że operator łopaty byłby szybszy.
Czy ktoś mógłby wyjaśnić szczegóły tej preferencji?
ruby
string
optimization
erinbrown
źródło
źródło
Odpowiedzi:
Dowód:
Więc
<<
zmienia oryginalny ciąg zamiast tworzenia nowego. Powodem tego jest to, że w rubya += b
jest skrótem składniowyma = a + b
(to samo dotyczy innych<op>=
operatorów), czyli przypisaniem. Z drugiej strony<<
jest aliasem,concat()
który zmienia odbiornik w miejscu.źródło
Array#join
jest wolniejszy niż używanie<<
.Dowód wydajności:
źródło
Znajomy, który uczy się Rubiego jako swojego pierwszego języka programowania, zadał mi to samo pytanie, przeglądając Strings in Ruby w serii Ruby Koans. Wyjaśniłem mu to za pomocą następującej analogii;
Masz szklankę wody, która jest do połowy pełna i musisz ją ponownie napełnić.
Najpierw weź nową szklankę, napełnij ją do połowy wodą z kranu, a następnie użyj drugiej do połowy pełnej szklanki do ponownego napełnienia szklanki. Robisz to za każdym razem, gdy potrzebujesz uzupełnić szklankę.
Drugi sposób, aby wziąć do połowy pełną szklankę i po prostu napełnić ją wodą prosto z kranu.
Pod koniec dnia będziesz mieć więcej szklanek do wyczyszczenia, jeśli zdecydujesz się wybrać nową szklankę za każdym razem, gdy będziesz musiał uzupełnić szklankę.
To samo dotyczy operatora łopaty i operatora plusa równego. Ponadto operator równorzędny wybiera nową „szklankę” za każdym razem, gdy trzeba ją uzupełnić, podczas gdy operator łopaty po prostu bierze tę samą szklankę i napełnia ją. Na koniec dnia kolejna zbiórka „szkła” dla operatora równorzędnego Plus.
źródło
To stare pytanie, ale właśnie je trafiłem i nie jestem w pełni zadowolony z istniejących odpowiedzi. Jest wiele dobrych punktów na temat tego, że łopata << jest szybsza niż konkatenacja + =, ale jest też kwestia semantyczna.
Zaakceptowana odpowiedź od @noodl pokazuje, że << modyfikuje istniejący obiekt w miejscu, podczas gdy + = tworzy nowy obiekt. Musisz więc zastanowić się, czy chcesz, aby wszystkie odwołania do ciągu odzwierciedlały nową wartość, czy też chcesz zostawić istniejące odniesienia w spokoju i utworzyć nową wartość ciągu do użytku lokalnego. Jeśli potrzebujesz, aby wszystkie odwołania odzwierciedlały zaktualizowaną wartość, musisz użyć znaku <<. Jeśli chcesz zostawić inne odniesienia w spokoju, musisz użyć + =.
Bardzo częstym przypadkiem jest to, że istnieje tylko jedno odniesienie do ciągu. W tym przypadku różnica semantyczna nie ma znaczenia i naturalne jest preferowanie znaku << ze względu na jego szybkość.
źródło
Ponieważ jest szybszy / nie tworzy kopii łańcucha <-> garbage collector nie musi działać.
źródło
malloc
/free
. Ponadto niektóre bardziej nowoczesne implementacje Rubiego prawdopodobnie całkowicie zoptymalizują alokację obiektów i łączenie ciągów znaków. OTOH, mutowanie obiektów jest straszne dla wydajności GC.Chociaż większość odpowiedzi
+=
jest wolniejsza, ponieważ tworzy nową kopię, ważne jest, aby o tym pamiętać+=
i<<
nie można ich używać zamiennie! Chcesz użyć każdego w różnych przypadkach.Użycie
<<
zmieni także wszelkie wskazywane zmienneb
. Tutaj również mutujemy,a
kiedy możemy tego nie chcieć.Ponieważ
+=
tworzy nową kopię, pozostawia również niezmienione zmienne, które na nią wskazują.Zrozumienie tego rozróżnienia może zaoszczędzić wiele bólu głowy, gdy masz do czynienia z pętlami!
źródło
Chociaż nie jest to bezpośrednia odpowiedź na twoje pytanie, dlaczego The Fully Upturned Bin zawsze był jednym z moich ulubionych artykułów Ruby. Zawiera również informacje o ciągach znaków w odniesieniu do czyszczenia pamięci.
źródło