Переменная ruby ​​как тот же объект (указатели?) - PullRequest
5 голосов
/ 24 августа 2011
>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5

как я могу установить 'b', чтобы фактически быть 'a', чтобы в примере переменная a также стала равной четырем. спасибо.

Ответы [ 7 ]

6 голосов
/ 24 августа 2011
class Ref
  def initialize val
    @val = val
  end

  attr_accessor :val

  def to_s
    @val.to_s
  end
end

a = Ref.new(4)
b = a

puts a   #=> 4
puts b   #=> 4

a.val = 5

puts a   #=> 5
puts b   #=> 5

Когда вы делаете b = a, b указывает на тот же объект, что и a (они имеют одинаковые object_id).

Когда вы делаете a = some_other_thing, завещаниеуказывает на другой объект, в то время как b остается неизменным.

Для Fixnum, nil, true и false вы не можете изменить значение без изменения object_id.Однако вы можете изменять другие объекты (строки, массивы, хэши и т. Д.) Без изменения object_id, , поскольку вы не используете присваивание (=) .

Примерсо строками:

a = 'abcd'
b = a

puts a  #=> abcd
puts b  #=> abcd

a.upcase!          # changing a

puts a  #=> ABCD
puts b  #=> ABCD

a = a.downcase     # assigning a

puts a  #=> abcd
puts b  #=> ABCD

Пример с массивами:

a = [1]
b = a

p a  #=> [1]
p b  #=> [1]

a << 2            # changing a

p a  #=> [1, 2]
p b  #=> [1, 2]

a += [3]          # assigning a

p a  #=> [1, 2, 3]
p b  #=> [1, 2]
2 голосов
/ 24 августа 2011

Вы не можете. Переменные содержат ссылки на значения, а не ссылки на другие переменные.

Вот что делает ваш пример кода:

a = 5 # Assign the value 5 to the variable named "a".
b = a # Assign the value in the variable "a" (5) to the variable "b".
b = 4 # Assign the value 4 to the variable named "b".
a # Retrieve the value stored in the variable named "a" (5).

См.эта статья для более глубокого обсуждения темы: передать по ссылке или передать по значению .

1 голос
/ 08 июня 2015

Один из вариантов, когда вы чувствуете, что хотите использовать операции прямого указателя, - это использовать метод замены Hashes, Arrays & Strings.

это полезно, когда вы хотите получить метод returnпеременная, которую задает метод с помощью метода, изменится позже и не захочет раздражать использование объекта-оболочки.

пример:

def hash_that_will_change_later
  params = {}
  some_resource.on_change do
    params.replace {i: 'got changed'}
  end
  params
end
a = hash_that_will_change_later
=> {}
some_resource.trigger_change!
a
{i: 'got changed'}

Вероятно, в целом лучшеиспользовать явные обертки объектов для таких случаев, но этот шаблон полезен для создания спецификаций / тестов асинхронного содержимого.

1 голос
/ 10 апреля 2014

Просто для справки.

>> a = 5
=> 5
>> a.object_id
=> 11
>> b = a
=> 5
>> b.object_id
=> 11
>> b = 4
=> 4
>> b.object_id
=> 9
>> a.object_id
=> 11
# We did change the Fixnum b Object.
>> Fixnum.superclass
=> Integer
>> Integer.superclass
=> Numeric
>> Numeric.superclass
=> Object
>> Object.superclass
=> BasicObject
>> BasicObject.superclass
=> nil

Надеюсь, это даст нам немного лучшее понимание объектов в Ruby.

1 голос
/ 25 августа 2011

Вы можете использовать массивы:

a = [5]
b = a
b[0] = 4
puts a[0]  #=>  4

Эта идея основана на этом ответе .

1 голос
/ 24 августа 2011

Как уже отмечалось, используемый вами синтаксис не может быть выполнен.Просто добавив это, хотя вы можете создать класс-обёртку, это зависит от того, что вы на самом деле хотите сделать

ruby-1.8.7-p334 :007 > class Wrapper
ruby-1.8.7-p334 :008?>   attr_accessor :number
ruby-1.8.7-p334 :009?>   def initialize(number)
ruby-1.8.7-p334 :010?>     @number = number
ruby-1.8.7-p334 :011?>   end
ruby-1.8.7-p334 :012?> end
 => nil 
ruby-1.8.7-p334 :013 > a = Wrapper.new(4)
 => #<Wrapper:0x100336db8 @number=4> 
ruby-1.8.7-p334 :014 > b = a
 => #<Wrapper:0x100336db8 @number=4> 
ruby-1.8.7-p334 :015 > a.number = 6
 => 6 
ruby-1.8.7-p334 :016 > a
 => #<Wrapper:0x100336db8 @number=6> 
ruby-1.8.7-p334 :017 > b
 => #<Wrapper:0x100336db8 @number=6> 
0 голосов
/ 24 августа 2011

Я не эксперт по Ruby. Но для технически сумасшедшего клуге ... это сработало бы, если бы вы чувствовали необходимость проходить через eval каждый раз, когда вы работали с переменной:

>> a = 5
=> 5
>> b = :a
=> :a
>> eval "#{b} = 4"
=> 4
>> eval "#{a}"
=> 4
>> eval "#{b}"
=> 4

Обратите внимание, что прямое использование b все равно даст вам :a, и вы не сможете использовать его в выражениях, которых нет в eval:

>> b
=> :a
>> b + 1
NoMethodError: undefined method `+' for :a:Symbol

... и, конечно, есть тонна предостережений. Например, вам нужно захватить binding и передать его в более сложных сценариях ...

«передать параметр по ссылке» в Ruby?

@Paul.s имеет ответ, если вы можете изменить точку объявления на объект-оболочку, но если вы можете управлять только точкой ссылки, то вот класс BasicReference, который я пробовал:

class BasicReference
    def initialize(r,b)
        @r = r
        @b = b
        @val = eval "#{@r}", @b
    end

    def val=(rhs)
        @val = eval "#{@r} = #{rhs}", @b
    end

    def val
        @val
    end
end

a = 5

puts "Before basic reference"
puts "   the value of a is #{a}"

b = BasicReference.new(:a, binding)

b.val = 4

puts "After b.val = 4"
puts "   the value of a is #{a}"
puts "   the value of b.val is #{b.val}"

Это выводит:

Before basic reference
   the value of a is 5
After b.val = 4
   the value of a is 4
   the value of b.val is 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...