2012-04-09 11 views
65

Właśnie zaczynam uczyć się Ruby (programowanie po raz pierwszy) i mam podstawowe pytanie syntaktyczne dotyczące zmiennych i różnych sposobów pisania kodu.Łączenie ciągów a interpolacja w Ruby

Chris Pine "Learn to Program" nauczył mnie pisać podstawowy program jak ten ...

num_cars_again= 2 
puts 'I own ' + num_cars_again.to_s + ' cars.' 

To jest w porządku, ale potem natknąłem samouczka na ruby.learncodethehardway.com i był uczy się pisać dokładnie taki sam program jak ten ...

num_cars= 2 
puts "I own #{num_cars} cars." 

obaj wyjście to samo, ale oczywiście opcja 2 jest znacznie krótszy sposób to zrobić.

Czy istnieje jakiś szczególny powód, dla którego powinienem używać jednego formatu w stosunku do drugiego?

+4

Ugh. Nienawidzę tego, jak często książki dla początkujących uczą cię nie-naturalnego sposobu robienia rzeczy, nie mówiąc przy tym, że istnieją alternatywy. +1 za uzasadnione pytanie, które nie zostało przegłosowane. –

+0

Istnieje więcej opcji omówionych na http://stackoverflow.com/questions/377768/string-concatenation-and-ruby – sameers

Odpowiedz

62

Ilekroć TIMTOWTDI (istnieje więcej niż jeden sposób, aby to zrobić), powinieneś poszukać plusów i minusów. Używanie "interpolacji ciąg" (drugi) zamiast "połączonego łańcucha znaków" (pierwszy):

Plusy:

  • jest mniej wpisując
  • automatycznie wywołuje to_s Ci
  • Więcej idiomatyczne w społeczności Ruby
  • Szybciej do wykonania w czasie wykonywania

Wady:

  • automatycznie wywołuje to_s dla ciebie (może Ci się, że miał ciąg, a reprezentacja to_s nie jest to, czego chciał, i ukrywa fakt, że nie był to łańcuch)
  • wymaga użycia " do wytyczają swój ciąg zamiast ' (być może masz nawyk korzystania ' lub wcześniej wpisany ciąg przy użyciu tego i dopiero później potrzebne do korzystania z interpolacji string)
+20

Nie zapomnij o aspekcie "to szybciej". W tym przykładzie konkatenacja ciągów musi w sumie utworzyć 3 ciągi, a interpolacja ciągów tylko jedna. –

+4

jeśli zależy Ci na benchmarkach, to jest również szybszy: [spróbuj mnie w REPL] (https://gist.github.com/1704455) – mrlee

+2

Dziękuję bardzo za odpowiedzi. Szybkie pytanie. Dlaczego książka Chrisa Pine'a nauczyła dłuższego sposobu na zrobienie tego? Może dla początkującego lepiej jest nauczyć się robić to dłużej? Jego książka mówi, że w większości przypadków jest leniwsza = lepsza, więc zastanawiam się, czy może z jakiegoś powodu (odkąd się dopiero uczę), powinienem nadal robić to po swojemu lub iść naprzód w lepszy sposób. Jakieś pomysły? –

3

@ user1181898 - IMHO, ponieważ łatwiej jest zobaczyć, co się dzieje. Do punktu @ Phrogza, interpolacja ciągów znaków automatycznie wywołuje dla ciebie to_s. Jako początkujący, musisz zobaczyć, co się dzieje "pod maską", abyś nauczył się tej koncepcji, a nie tylko uczenie się na pamięć.

Pomyśl o tym, jak uczyć się matematyki. Uczysz się "długiej" drogi, aby zrozumieć pojęcia, dzięki czemu możesz podejmować skróty, gdy tylko wiesz, co robisz. Mówię z doświadczenia b/c Nie jestem jeszcze zaawansowany w Ruby, ale popełniłem wystarczająco dużo błędów, aby doradzić ludziom, czego nie robić. Mam nadzieję że to pomoże.

+0

Wielkie dzięki, to prawda! –

7

Zarówno interpolacja, jak i konkubinacja mają swoją własną siłę i słabość. Poniżej przedstawiłem benchmark, który wyraźnie pokazuje, gdzie stosować konkatinację i gdzie użyć interpolacji.

require 'benchmark' 

iterations = 1_00_000 
firstname = 'soundarapandian' 
middlename = 'rathinasamy' 
lastname = 'arumugam' 

puts 'With dynamic new strings' 
puts '====================================================' 
5.times do 
    Benchmark.bm(10) do |benchmark| 
    benchmark.report('concatination') do 
     iterations.times do 
     'Mr. ' + firstname + middlename + lastname + ' aka soundar' 
     end 
    end 

    benchmark.report('interpolaton') do 
     iterations.times do 
     "Mr. #{firstname} #{middlename} #{lastname} aka soundar" 
     end 
    end 
    end 
    puts '--------------------------------------------------' 
end 

puts 'With predefined strings' 
puts '====================================================' 
5.times do 
    Benchmark.bm(10) do |benchmark| 
    benchmark.report('concatination') do 
     iterations.times do 
     firstname + middlename + lastname 
     end 
    end 

    benchmark.report('interpolaton') do 
     iterations.times do 
     "#{firstname} #{middlename} #{lastname}" 
     end 
    end 
    end 
    puts '--------------------------------------------------' 
end 

A poniżej jest Benchmark wynik

Without predefined strings 
==================================================== 
       user  system  total  real 
concatination 0.170000 0.000000 0.170000 ( 0.165821) 
interpolaton 0.130000 0.010000 0.140000 ( 0.133665) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.180000 0.000000 0.180000 ( 0.180410) 
interpolaton 0.120000 0.000000 0.120000 ( 0.125051) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.140000 0.000000 0.140000 ( 0.134256) 
interpolaton 0.110000 0.000000 0.110000 ( 0.111427) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.130000 0.000000 0.130000 ( 0.132047) 
interpolaton 0.120000 0.000000 0.120000 ( 0.120443) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.170000 0.000000 0.170000 ( 0.170394) 
interpolaton 0.150000 0.000000 0.150000 ( 0.149601) 
-------------------------------------------------- 
With predefined strings 
==================================================== 
       user  system  total  real 
concatination 0.070000 0.000000 0.070000 ( 0.067735) 
interpolaton 0.100000 0.000000 0.100000 ( 0.099335) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.060000 0.000000 0.060000 ( 0.061955) 
interpolaton 0.130000 0.000000 0.130000 ( 0.127011) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.090000 0.000000 0.090000 ( 0.092136) 
interpolaton 0.110000 0.000000 0.110000 ( 0.110224) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.080000 0.000000 0.080000 ( 0.077587) 
interpolaton 0.110000 0.000000 0.110000 ( 0.112975) 
-------------------------------------------------- 
       user  system  total  real 
concatination 0.090000 0.000000 0.090000 ( 0.088154) 
interpolaton 0.140000 0.000000 0.140000 ( 0.135349) 
-------------------------------------------------- 

Wnioski

Jeśli ciągi już zdefiniowane i pewność, że nigdy nie będzie zerowe wykorzystanie concatination jeszcze używać interpolation.Use odpowiedni jeden, który spowoduje w lepszej wydajności niż ta, która jest łatwa do zaciśnięcia.

+0

z której wersji Ruby korzystałeś? –

1

Jeśli używasz łańcucha jako bufora, odkryłem, że używanie konkatenacji (String#concat) jest szybsze.

require 'benchmark/ips' 

puts "Ruby #{RUBY_VERSION} at #{Time.now}" 
puts 

firstname = 'soundarapandian' 
middlename = 'rathinasamy' 
lastname = 'arumugam' 

Benchmark.ips do |x| 
    x.report("String\#<<") do |i| 
     buffer = String.new 

     while (i -= 1) > 0 
      buffer << 'Mr. ' << firstname << middlename << lastname << ' aka soundar' 
     end 
    end 

    x.report("String interpolate") do |i| 
     buffer = String.new 

     while (i -= 1) > 0 
      buffer << "Mr. #{firstname} #{middlename} #{lastname} aka soundar" 
     end 
    end 

    x.compare! 
end 

Wyniki:

Ruby 2.3.1 at 2016-11-15 15:03:57 +1300 

Warming up -------------------------------------- 
      String#<< 230.615k i/100ms 
    String interpolate 234.274k i/100ms 
Calculating ------------------------------------- 
      String#<<  2.345M (± 7.2%) i/s -  11.761M in 5.041164s 
    String interpolate  1.242M (± 5.4%) i/s -  6.325M in 5.108324s 

Comparison: 
      String#<<: 2344530.4 i/s 
    String interpolate: 1241784.9 i/s - 1.89x slower 

na oko, powiedziałbym, że interpolacja generuje tymczasowy łańcuch, który jest dlaczego to wolniej.