Чи проходить Ruby за посиланням чи за значенням?


248
@user.update_languages(params[:language][:language1], 
                       params[:language][:language2], 
                       params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------" 
                + lang_errors.full_messages.inspect

if params[:user]
  @user.state = params[:user][:state]
  success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------" 
                + lang_errors.full_messages.inspect

if lang_errors.full_messages.empty?

@userоб'єкт додає помилки до lang_errorsзмінної в update_lanugagesметоді. Коли я виконую збереження на @userоб'єкті, я втрачаю помилки, які були спочатку збережені у lang_errorsзмінній.

Хоча те, що я намагаюся зробити, було б більше хаком (який, здається, не працює). Я хотів би зрозуміти, чому значення змінних розмиваються. Я розумію прохід за посиланням, тому я хотів би знати, як значення може зберігатися в цій змінній, не вимиваючись.


Я також помічаю, що мені вдається зберегти це значення в клонованому об’єкті
Сід

1
Подивіться на відповідь Абе Волкера. Але після того, як пробіг навколо цього блоку, ось як я це сказав. при передачі об'єкта Foo в процедуру передається копія посилання на об'єкт, бар, значення Pass. ви не можете змінити об'єкт, на який вказує Foo, але ви можете змінити вміст об'єкта, на який він вказує. Отже, якщо ви передаєте масив, вміст масиву можна змінити, але ви не можете змінити, на який масив посилається. приємно мати можливість використовувати методи Foo, не турбуючись про те, щоб зіпсувати інші залежності від Foo.
bobbdelsol

Відповіді:


244

У традиційній термінології Рубі є суворо прохідною цінністю . Але це насправді не те, що ви тут просите.

У Ruby немає поняття чистого, нереференційного значення, тому ви, звичайно, не можете його передати методу. Змінні - це завжди посилання на об'єкти. Для того, щоб отримати об’єкт, який не зміниться з-під вас, вам потрібно копіювати або клонувати об'єкт, який вам передали, таким чином, даючи об’єкт, на який ніхто інший не має посилання. (Навіть це не є куленепроникним - обидва стандартні методи клонування роблять неглибоку копію, тому змінні екземпляра клону все ще вказують на ті самі об’єкти, що і оригінали. Якщо об'єкти, на які посилається ivars, мутують, це буде все ще відображається в копії, оскільки вона посилається на ті самі об’єкти.)


88
Ruby - прохідна цінність . Ні, якщо. Не буває. Немає винятків. Якщо ви хочете знати , є чи Ruby (або будь-який інший мову) є пройти за посиланням або передати за значенням , просто спробуйте це: def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}".
Йорг W Міттаг

95
@ JörgWMittag: Так, але плутанина ОП насправді не є прохідною цінністю або проходом посилань у строгому сенсі CS цих слів. Що йому бракувало, це те, що "значення", які ви передаєте, - це посилання. Я відчував, що просто сказати "Це прохідна цінність" було б педантичним і зробить ОП сумлінною послугою, оскільки це насправді не те, що він мав на увазі. Але дякую за роз’яснення, адже це важливо для майбутніх читачів, і я мав би його включити. (Я завжди розривається між включенням додаткової інформації та не бентежать людей.)
Чак,

16
Не погоджуючись з @Jorg. Рубі проходять через посилання, він просто змінює посилання. Спробуйте скоріше це: def foo (bar) bar.replace 'reference' end; baz = 'значення'; foo (baz); ставить "Рубі проходить повз - # {baz}"
pguardiario

15
@pguardiario: Я думаю, це насправді лише питання визначень. Ви використовуєте визначення "пройти посилання", яке ви особисто придумали, тоді як Йорг використовує традиційне визначення інформатики. Звичайно, мені ніхто не підказує, як вживати слова - я просто думаю, що важливо пояснити, що зазвичай означає цей термін . У традиційній термінології Ruby є прохідною цінністю, але самі значення є посиланнями. Я цілком розумію, чому ви та ОП любите сприймати це як прохідне посилання - це просто не традиційне значення цього терміна.
Чак

7
Все в Ruby є об'єктом, тому Ruby не є ні прохідним значенням, ні пропускним посиланням, принаймні в тому сенсі, що ці терміни використовуються в C ++. "пройти посилання на об'єкт" може бути кращим способом описати, що робить Рубі. Зрештою, найкращим моментом може бути не приділяти занадто багато сенсу жодному з цих термінів, а просто добре зрозуміти поведінку, що насправді відбувається.
Девід Вінієцький

424

З іншими відповідачами все правильно, але друг попросив мене пояснити це йому, і що це насправді зводиться до того, як Рубі обробляє змінні, тож я подумав, що поділюсь простими малюнками / поясненнями, які я написав для нього (вибачення за тривалість і, ймовірно, деяке спрощення):


Q1: Що станеться, якщо новій змінній strпризначити значення 'foo'?

str = 'foo'
str.object_id # => 2000

введіть тут опис зображення

Відповідь: Створена мітка str, яка вказує на об'єкт 'foo', який, за станом цього інтерпретатора Ruby, знаходиться в пам'яті 2000.


Q2: Що відбувається, коли ви призначите існуючу змінну strновому об'єкту за допомогою =?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

введіть тут опис зображення

A: Мітка strтепер вказує на інший об'єкт.


Q3: Що відбувається , коли ви призначаєте нову змінну =в str?

str2 = str
str2.object_id # => 2002

введіть тут опис зображення

A: Створена нова мітка, що називається str2, що вказує на той самий об'єкт, що і str.


Q4: Що станеться, якщо об'єкт, на який посилається, strі str2змінений?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

введіть тут опис зображення

Відповідь: Обидві мітки все ще вказують на один і той же об'єкт, але сам об’єкт мутував (його вміст змінився на щось інше).


Як це стосується початкового питання?

Це в основному те саме, що відбувається в Q3 / Q4; метод отримує власну приватну копію змінної / label ( str2), яка передається йому ( str). Він не може змінити, на який об’єкт str вказує мітка , але він може змінити вміст об'єкта, на який вони обоє посилаються, що містить ще:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004

1
Роберт Хітон також нещодавно блогував
Майкл Реннер

48

Ruby використовує "пройти посилання на об'єкт"

(Використовуючи термінологію Python.)

Скажімо, Ruby використовує "pass by value" або "pass by reference" насправді недостатньо описовий, щоб бути корисним. Я думаю, як більшість людей це знає в наші дні, що термінологія ("значення" проти "посилання") походить від C ++.

У C ++ "передавати значення" означає, що функція отримує копію змінної, і будь-які зміни в копії не змінюють оригінал. Це справедливо і для об’єктів. Якщо ви передаєте об'єктну змінну за значенням, то весь об'єкт (включаючи всі його члени) буде скопійовано, і будь-які зміни членів не змінять цих членів на вихідний об'єкт. (Це інакше, якщо ви передасте вказівник за значенням, але у Ruby все одно немає вказівників, AFAIK.)

class A {
  public:
    int x;
};

void inc(A arg) {
  arg.x++;
  printf("in inc: %d\n", arg.x); // => 6
}

void inc(A* arg) {
  arg->x++;
  printf("in inc: %d\n", arg->x); // => 1
}

int main() {
  A a;
  a.x = 5;
  inc(a);
  printf("in main: %d\n", a.x); // => 5

  A* b = new A;
  b->x = 0;
  inc(b);
  printf("in main: %d\n", b->x); // => 1

  return 0;
}

Вихід:

in inc: 6
in main: 5
in inc: 1
in main: 1

У C ++ "пройти через посилання" означає, що функція отримує доступ до вихідної змінної. Він може призначити ціле нове буквальне ціле число, і початкова змінна також матиме це значення.

void replace(A &arg) {
  A newA;
  newA.x = 10;
  arg = newA;
  printf("in replace: %d\n", arg.x);
}

int main() {
  A a;
  a.x = 5;
  replace(a);
  printf("in main: %d\n", a.x);

  return 0;
}

Вихід:

in replace: 10
in main: 10

Ruby використовує pass by value (у значенні C ++), якщо аргумент не є об'єктом. Але в Ruby все є об'єктом, тому насправді в Ruby немає значення пропуску за значенням C ++.

У Ruby використовується "пройти посилання на об'єкт" (для використання термінології Python):

  • Всередині функції будь-якого з членів об'єкта можуть бути призначені їм нові значення, і ці зміни зберігатимуться після повернення функції. *
  • Всередині функції присвоєння цілому новому об'єкту змінній змушує змінну припиняти посилання на старий об'єкт. Але після повернення функції початкова змінна все ще посилатиметься на старий об’єкт.

Тому Рубі не використовує "пройти посилання" в сенсі С ++. Якщо це було, то присвоєння нового об'єкта змінній всередині функції призведе до забуття старого об'єкта після повернення функції.

class A
  attr_accessor :x
end

def inc(arg)
  arg.x += 1
  puts arg.x
end

def replace(arg)
  arg = A.new
  arg.x = 3
  puts arg.x
end

a = A.new
a.x = 1
puts a.x  # 1

inc a     # 2
puts a.x  # 2

replace a # 3
puts a.x  # 2

puts ''

def inc_var(arg)
  arg += 1
  puts arg
end

b = 1     # Even integers are objects in Ruby
puts b    # 1
inc_var b # 2
puts b    # 1

Вихід:

1
2
2
3
2

1
2
1

* Ось чому в Ruby, якщо ви хочете змінити об'єкт у функції, але забути про ці зміни, коли функція повертається, тоді ви повинні явно зробити копію об'єкта, перш ніж вносити тимчасові зміни в копію.


Ваша відповідь найкраща. Я також хочу розмістити простий приклад def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
fangxing

Це правильна відповідь! Це також дуже добре пояснено тут: robertheaton.com/2014/07/22/… . Але то , що я до сих пір не розумію , це: def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}". Це друкує "Ruby є прохідною вартістю". Але змінна всередині fooперепризначена. Якщо barце масив, переназначення не вплине baz. Чому?
haffla

Я не розумію вашого запитання. Я думаю, вам слід задати зовсім нове запитання, а не запитувати тут коментарі.
David Winiecki

42

Чи проходить Ruby за посиланням чи за значенням?

Ruby - прохідна цінність. Завжди. Немає винятків. Ні, якщо. Не буває.

Ось проста програма, яка демонструє цей факт:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

15
@DavidJ.: «Помилка тут в тому , що локальний параметр перепризначений (вказує на нове місце в пам'яті)» - Це не помилка, це визначення з передачі за значенням . Якби Ruby були прохідними посиланнями, то переназначення на аргумент локального методу, що зв'язує у виклику, також призначало б прив'язку локальної змінної у виклику. Котрий цього не зробив. Ерго, Рубі - прохідна цінність. Те, що якщо ви змінюєте змінне значення, значення змінюється абсолютно не має значення, саме так працює стан змінних. Рубі - це не чисто функціональна мова.
Йорг W Міттаг

5
Дякуючи Йоргу, що він захистив справжнє визначення поняття "пропускна вартість". Це чітко тане наш мозок, коли значення насправді є еталонним, хоча рубін завжди передає побічну вартість.
Дуглас

9
Це софістика. Практичне розмежування "пройти за значенням" і "пройти за посиланням" є семантичним, а не синтаксичним. Ви б сказали, що масиви C є прохідними за значенням? Звичайно, ні, навіть якщо ви передаєте ім'я масиву функції, ви передаєте незмінний покажчик, і лише ті дані, на які вказівник посилається, можуть бути мутовані. Очевидно, що типи значень у Ruby передаються за значенням, а типи посилань передаються за посиланням.
dodgethesteamroller

3
@dodgethesteamroller: і Ruby, і C - прохідні значення. Завжди. Ні винятків, ні ifs no buts. Різниця між прохідною цінністю і прохідною посиланням полягає в тому, передаєте ви значення опорним точкам або передаєте посилання. C завжди передає значення, ніколи не посилається. Значення може бути, а може і не бути вказівником, але те, що це значення, не має значення для того, чи передається воно в першу чергу. Ruby також завжди передає значення, ніколи не посилання. Це значення завжди є вказівником, але, знову ж таки, це не має значення.
Йорг W Міттаг

44
Ця відповідь, строго кажучи правдива , не дуже корисна . Те, що значення, яке передається завжди є вказівником, не має значення. Це джерело плутанини для людей, які намагаються навчитися, і ваша відповідь абсолютно нічого не допомагає в цій плутанині.

20

Ruby є прохідною цінністю у строгому значенні, АЛЕ значення є посиланнями.

Це можна назвати " пропускним посиланням за значенням ". Ця стаття має найкраще пояснення, яке я прочитав: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/

Коефіцієнт проходження посилання може бути коротко пояснений так:

Функція отримує посилання на (і отримає доступ) до того самого об'єкта в пам'яті, що використовується абонентом. Однак він не отримує вікно, в якому абонент зберігає цей об'єкт; як і у прохідному значенні за значенням, функція забезпечує власне поле і створює нову змінну для себе.

Отримана поведінка насправді є комбінацією класичних визначень прохідних посилань та пропускних значень.


"пройти посилання за значенням" - це та сама фраза, яку я використовую для опису аргументу Рубі. Я думаю, що це найточніша та найкоротша фраза.
Уейн Конрад

16

Вже є кілька чудових відповідей, але я хочу опублікувати визначення пари влади з цього приводу, але також сподіваючись, що хтось може пояснити, що сказав влада Матц (творець Рубі) та Девід Фланаган у своїй чудовій книзі О'Рейлі, Мова програмування Ruby .

[від 3.8.1: Посилання на об'єкт]

Коли ви передаєте об'єкт методу в Ruby, це посилання на об'єкт передається методу. Це не сам об'єкт, і це не посилання на посилання на об'єкт. Ще один спосіб сказати це, що аргументи методу передаються за значенням, а не за посиланням , але що передані значення є посиланнями на об'єкти.

Оскільки посилання на об'єкти передаються методам, методи можуть використовувати ці посилання для зміни базового об'єкта. Ці зміни потім видно, коли метод повертається.

Це все має сенс для мене до останнього абзацу, і особливо до останнього речення. Це в кращому випадку оманливе, а в гіршому - бентежне. Як, в будь-якому випадку, зміни в передаваному посиланні значення можуть змінити базовий об'єкт?


1
Оскільки посилання не змінюється; основним об'єктом є.
dodgethesteamroller

1
Тому що об’єкт є змінним. Рубі - не суто функціональна мова. Це цілком ортогонально для передачі посилань порівняно з проходом за значенням (за винятком того, що в чисто функціональній мові "пропуск за значенням" і "посилання за посиланням" завжди дають однакові результати, тому мова могла б використовуйте або те, і те, і інше, коли ви ніколи не знаєте).
Йорг W Міттаг

Хорошим прикладом може бути, якщо замість присвоєння змінної функції, ви подивитесь на випадок передачі хеша функції та злиття! на пройдений хеш. Оригінальний хеш закінчується модифікованим.
elc

16

Чи проходить Ruby за посиланням чи за значенням?

Рубі - це посилання. Завжди. Немає винятків. Ні, якщо. Не буває.

Ось проста програма, яка демонструє цей факт:

def foo(bar)
  bar.object_id
end

baz = 'value'

puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"

=> 2279146940 Ruby - це посилання 2279146940, оскільки об'єкти_id (адреси пам'яті) завжди однакові;)

def bar(babar)
  babar.replace("reference")
end

bar(baz)

puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"

=> деякі люди не розуміють, що це посилання, оскільки місцеве призначення може мати перевагу, але це явно прохідне посилання


Це єдина правильна відповідь і представляє деякі приємні мотиви: Спробуйте a = 'foobar'; b = a; b [5] = 'z', і a, і b буде змінено.
Martijn

2
@Martijn: ваш аргумент не зовсім вірний. Давайте переглянемо ваш код за заявою. a = 'foobar' створює нове посилання, що вказує на 'foobar'. b = a створює друге посилання на ті самі дані, що і a. b [5] = 'z' змінює шостий символ значення, на який посилається b, на 'z' (значення, яке збігається також випадково, змінене). Ось чому "обидва модифікуються" у ваших термінах, а точніше, чому "значення, на яке посилаються обидві змінні, змінюється".
Lukas_Skywalker

2
Ви нічого не робите з посиланням на ваш barметод. Ви просто модифікуєте об'єкт, на який вказує посилання , але не саму посилання. Єдиний спосіб змінити посилання в Ruby - це шляхом призначення. Ви не можете змінювати посилання шляхом виклику методів у Ruby, оскільки методи можна викликати лише на об'єктах, а посилання не є об'єктами в Ruby. Ваш зразок коду демонструє, що Ruby має змінний стан (про який тут не йдеться), однак він нічого не робить для висвітлення різниці між прохідною вартістю та пропускною посиланням.
Йорг W Міттаг

1
Коли хтось запитує, чи є мова "проходом посилань", вони зазвичай хочуть знати, коли ви передаєте щось функції, і функція її змінює, чи буде вона змінена поза функцією. Для Рубі відповідь - так. Ця відповідь корисна для того, щоб продемонструвати, що відповідь @ JörgWMittag вкрай не допомагає.
Toby 1 Kenobi

@ Toby1Kenobi: Ви, звичайно, можете безкоштовно використовувати власне особисте визначення терміна "пропускна вартість", яке відрізняється від загального, що широко використовується. Однак якщо ви це зробите, ви повинні бути готові до того, що люди будуть плутатись, особливо якщо ви нехтуєте розкрити той факт, що ви говорите про зовсім інше, в деяких аспектах навіть протилежне поняття, ніж це роблять усі інші. Зокрема, "прохідний посилання" не стосується того, чи може "щось", що передається, може бути змінено чи, а не те, що це "щось", зокрема, чи це посилання ...
Йорг W Міттаг

8

Параметри - це копія оригіналу посилання. Отже, ви можете змінювати значення, але не можете змінити початкові посилання.


2

Спробуйте це:--

1.object_id
#=> 3

2.object_id
#=> 5

a = 1
#=> 1
a.object_id
#=> 3

b = 2
#=> 2
b.object_id
#=> 5

ідентифікатор a містить object_id 3 для об'єкта значення 1, а ідентифікатор b містить object_id 5 для об'єкта значення 2.

Тепер зробіть це: -

a.object_id = 5
#=> error

a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2

a.object_id 
#=> 5

Тепер і a, і b містять один і той же object_id 5, який посилається на об'єкт значення 2. Отже, змінна Ruby містить object_ids для позначення об'єктів значення.

Виконання наступних дій також дає помилку: -

c
#=> error

але це не призведе до помилок: -

5.object_id
#=> 11

c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11 

a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true

a
#=> Value at a
#=> 11

Тут ідентифікатор повертає об'єкт значення 11, ідентифікатор якого об'єкта 23, тобто object_id 23 знаходиться в ідентифікаторі a, Тепер ми бачимо приклад за допомогою методу.

def foo(arg)
  p arg
  p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23

arg in foo присвоюється зворотним значенням x. З цього чітко видно, що аргумент передається за значенням 11, а значення 11, будучи самим об'єктом, має унікальний ідентифікатор об'єкта 23.

Тепер це також:

def foo(arg)
  p arg
  p arg.object_id
  arg = 12
  p arg
  p arg.object_id
end

#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23

Тут ідентифікатор arg спочатку містить object_id 23 для посилання 11, а після внутрішнього присвоєння значенню об'єкта 12, він містить object_id 25. Але він не змінює значення, на яке посилається ідентифікатор x, який використовується в методі виклику.

Отже, Ruby передається за значенням, а змінні Ruby не містять значень, але містять посилання на об'єкт значення.


1

Інтерпретується Рубі. Змінні - це посилання на дані, але не самі дані. Це полегшує використання однієї змінної для даних різних типів.

Призначення lhs = rhs потім копіює посилання на rhs, а не на дані. Це відрізняється від інших мов, таких як C, де присвоєння копіює дані в lhs з rhs.

Отже, для виклику функції змінна передана, скажімо x, дійсно копіюється в локальну змінну у функції, але x є посиланням. Потім будуть дві копії посилання, обидві посилання на однакові дані. Один буде в абонента, один у функції.

Потім призначення у функції копіює нове посилання на версію функції x. Після цього версія абоненту x залишається незмінною. Це все ще посилання на вихідні дані.

На відміну від цього, використання методу .replace на x призведе до рубіну для копіювання даних. Якщо замість використовується перед будь-якими новими призначеннями, то дійсно абонент також побачить зміни даних у своїй версії.

Аналогічно, доки оригінальна посилання знаходиться в такті для переданої змінної, змінні екземпляра будуть такими, які бачить абонент. У рамках об'єкта змінні екземплярів завжди мають найновіші опорні значення, незалежно від того, надані вони абонентом або встановлені у функції, в яку передано клас.

"Виклик за значенням" або "Виклик за посиланням" тут заплутаний через плутанину над "=" У компільованих мовах "=" є копією даних. Тут у цій інтерпретованій мові '=' є довідковою копією. У прикладі ви посилаєте посилання, за яким йде копія посилання, хоч '=', що клобує оригінал, переданий посиланням, і тоді люди, які говорять про нього, ніби '=', були копією даних.

Щоб відповідати визначенню, ми повинні зберігати ".замінити", оскільки це копія даних. З точки зору ".замінити" ми бачимо, що це справді проходить через посилання. Крім того, якщо ми проходимо через налагоджувач, ми бачимо передані посилання, оскільки змінні є посиланнями.

Однак якщо ми повинні зберігати '=' як систему відліку, то насправді ми отримуємо бачити передані дані до призначення, і тоді ми не отримуємо їх більше після призначення, поки дані абонента залишаються незмінними. На поведінковому рівні це передається за значенням до тих пір, поки ми не вважатимемо передане значення складовим - оскільки ми не зможемо зберегти його частину, змінюючи іншу частину в одному призначенні (як це призначення змінює посилання і оригінал виходить за межі). Також буде бородавка, в цьому екземплярі змінні в об'єктах будуть посиланнями, як і всі змінні. Таким чином, ми будемо змушені говорити про передачу "посилань за значенням" і повинні використовувати відповідні місця.


1

Слід зазначити, що вам не доведеться навіть використовувати метод "заміна", щоб змінити початкове значення. Якщо ви призначите одне з хеш-значень для хеша, ви змінюєте початкове значення.

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

Ще одне, що я знайшов. Якщо ви передаєте числовий тип, всі числові типи незмінні, і таким чином ARE проходять за значенням. Функція заміни, яка працювала з рядком вище, НЕ працює для жодного з числових типів.
Дон Карр

1
Two references refer to same object as long as there is no reassignment. 

Будь-які оновлення в одному об'єкті не посилаються на нову пам'ять, оскільки вона все ще знаходиться в одній пам'яті. Ось кілька прикладів:

    a = "first string"
    b = a



    b.upcase! 
    => FIRST STRING
    a
    => FIRST STRING

    b = "second string"


a
    => FIRST STRING
    hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"

    hash
    => {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}

    def change(first_sub_hash)
    first_sub_hash[:third_key] = "third_value"
    end

    change(first_sub_hash)

    hash
    =>  {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}

0

Так, але ....

Рубі передає посилання на об'єкт, і оскільки все, що знаходиться в рубіні, є об'єктом, то можна сказати, що це передається за посиланням.

Я не погоджуюся з публікаціями тут, стверджуючи, що це передається за вартістю, що мені здається педантичним, символічним іграми.

Однак насправді це "приховує" поведінку, оскільки більшість операцій рубін забезпечує "поза коробкою" - наприклад, рядкові операції, створюють копію об'єкта:

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

Це означає, що більшу частину часу вихідний об'єкт залишається незмінним, надаючи вигляд, що рубін "проходить за значенням".

Звичайно, розробляючи власні заняття, розуміння деталей такої поведінки має важливе значення як для функціональної поведінки, ефективності пам’яті та продуктивності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.