Ссылка на массив в Ruby?

Могу ли я иметь ссылку на ячейку массива в Ruby? В C++ я могу сделать что-то вроде:

int& ref = arr[x][y];

а потом работать с переменной ref без необходимости печатать весь arr[x][y],

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

4 ответа

Все значения в ruby ​​являются ссылками, так что это, безусловно, возможно, но с некоторыми важными ограничениями. Единственное предостережение в том, что ruby ​​НЕ ПРЯМО поддерживает многомерные массивы, но вы можете реализовать его как массив массивов или как хеш-код с ключами от кортежей.

Этого можно добиться в тех случаях, когда значение в (x, y) уже было установлено путем присвоения значения в заданных координатах. Если в этом месте в настоящее время нет значения, то вы должны инициализировать это значение, прежде чем сможете иметь ссылку на него:

# if x and y are indices and a is your "multidimensional array"

a[x][y] = 'First Value'  # Initial value at (x, y)

ref = a[x][y]  # take a reference to the value referenced by a[x][y]

ref.gsub! 'First', 'Second'

a[x][y]  # => 'Second Value'

Имейте в виду, что оператор присваивания в ruby ​​обычно означает "сделать ссылку на левую сторону ссылкой на значение справа". Это означает, что если вы используете оператор присваивания в вашей ссылке, то вы фактически заставляете его ссылаться на новое значение:

a[x][y] = 1     # Initialize value with 1
ref = a[x][y]   # Take the reference

ref += 1        # Assignment    
ref             # => 2
a[x][y]         # => 1

Вы могли бы добиться большего успеха, используя Hash и вводить хеш с кортежами ваших координат, а затем использовать эти кортежи для получения ссылок на определенные местоположения:

a = {}
loc = [x, y]

a[loc] = 'First Value'     # Initial value
a[[x,y]]  # => 'First Value'

a[loc] = 'Second Value'  # Assignment
a[[x,y]]  # => 'Second Value'

a[loc] = 1  # Assignment
a[loc] += 1 # Assignment
a[[x,y]]  # => '2'

В языке высокого уровня, таком как ruby, все переменные являются ссылками, и нет никаких "указателей" или уровней косвенных указаний, таких как C или C++, вы должны создать объекты для хранения этих ссылок, чтобы получить похожее поведение

Это то, что я бы сделал на ruby

Предположим, вам нужно сохранить "указатель" на массив ruby, а затем создать класс для доступа к массиву в заданном индексе (нет такой вещи, как получение "указателя" на значение в ruby).

class ArrayPointer
  def initialize(array, index)
    @array = array
    @index = index
  end

  def read
    @array[index]
  end

  def write(value)
    @array[index] = value
  end
end

Затем вы используете фразу таким образом

array = [1, 2, 3]
pointer = ArrayPointer.new(array, 1)

pointer.write(20)
puts array # [1, 20, 3]

Вы также можете получить "указатели" на локальные переменные, но это слишком странно и необычно в мире ruby, и это почти не имеет смысла

Обратите внимание, что этот вид кода странный и не распространенный в ruby, но с дидактической точки зрения интересно сравнить два замечательных языка, таких как Ruby и C

В объектно-ориентированной природе ruby ​​предпочтительно проектировать хорошие абстракции (например, вместо использования массива для представления ваших данных, если предпочтительнее определить класс с помощью методов, таких как метод ruby), прежде чем использовать только элементарные структуры, такие как Array или Hash для представлять данные, используемые вашей программой (последний подход, распространенный в C, это не метод ruby)

Чтобы ref продолжал указывать на фактические данные arr[x][y] в любой момент времени, можно написать его как метод:

def ref
  ar[1][1]
end

Ruby считается проходным по значению, поэтому, чтобы ответить на ваш вопрос (не передаваемый по ссылке, как C++), напрямую выполнить то, что вы просите, невозможно.

В этом ответе Эйба есть действительно хороший пост, который вы должны прочитать:

Ruby передается по ссылке или по значению?

Другие вопросы по тегам