Как вы вызываете метод класса из метода инициализации?

Я пытаюсь вызвать метод в классе во время его метода инициализации. Разве это не разрешено? Изначально у меня был метод вне класса, чтобы попытаться использовать его как глобальный метод. Текущий метод пытается вернуть созданную матрицу, а затем метод инициализации сохраняет возвращенную матрицу в переменную экземпляра.

class Member
  def setMatrix(a, i, l)
    puts "here"
    m = Matrix.zero(6)
    m[0,0] = a*l**2/i
    m[0,3] = -a*l**2/i
    m[1,1] = 12
    m[1,2] = 6*l
    m[1,4] = -12
    m[1,5] = 6*l
    m[2,1] = 6*l
    m[2,2] = 4*l**2
    m[2,4] = -6*l
    m[2,5] = 2*l**2
    m[3,0] = -a*l**2/i
    m[3,3] = a*l**2/i
    m[4,1] = -12
    m[4,2] = -6*l
    m[4,4] = 12
    m[4,5] = -6*l
    m[5,1] = 6*l
    m[5,2] = 2*l**2
    m[5,4] = -6*l
    m[5,5] = 4*l**2
    return m
    #@k = m
   end

   def initialize(a, i, l)
     @area = a
     @i = i
     @length = l
     @k = setMatrix(a, i, l)
    end
end

Выполнение этого возвращает эту ошибку

`'setMatrix': private method '[]=' called for #<Matrix:0x00000001186e00> (NoMethodError)
from truss_solver.rb:71:in 'initialize'
from truss_solver.rb:86:in 'new'
from truss_solver.rb:86:in 'block in <main>'
from truss_solver.rb:85:in 'each'
from truss_solver.rb:85:in '<main>'`

Я хотел бы сделать переменную экземпляра матрицы при создании экземпляра класса. Я также пытался, чтобы метод setMatrix сохранял матрицу напрямую в @k вместо возврата матрицы, и это дало аналогичную ошибку. Как еще я могу добиться того, чего хочу?


person rangeme    schedule 21.04.2016    source источник
comment
Вы сказали, что это возвращает эту ошибку... Предположительно, это включает создание экземпляра Member (например, Member.new(1,2,3)), который не показан.   -  person Cary Swoveland    schedule 21.04.2016


Ответы (2)


Ничто не мешает вам вызывать методы внутри initialize, там нет особого поведения, но здесь вы вызываете метод private в другом классе.

Я не знаю, почему он установлен private, и некоторые люди заметили это кажется проблемой, так что вы всегда можете просто переборщить:

matrix.send(:[]=, 1, 2, 3)

Это кажется запутанным, и исправление, как рекомендуется в этом посте, может помочь упростить ситуацию:

class Matrix
  def []=(row, column, value)
    @rows[row][column] = value
  end
end

Вы также можете создать подкласс от Matrix до MutableMatrix и включить этот метод.

В качестве примечания, соглашения об именах методов в Ruby — underscore_style, и включение явного return в конце не обязательно, это подразумевается. m в одиночку сделал бы эту работу.

person tadman    schedule 21.04.2016
comment
Кроме того, вы должны raise ArgumentError if row >= row_count || column >= column_count убедиться, что row и column находятся в пределах матрицы. - person Stefan; 21.04.2016

Давайте получим больше информации:

require 'matrix'
Matrix.instance_methods.include?(:[]=)
  #=> false
Matrix.private_instance_methods.include?(:[]=)
  #=> true

Последнее было для меня неожиданностью. Учитывая, что объекты Matrix неизменяемы, метода :[]= быть не должно. (Это похоже на 2=4, что, конечно, вызывает исключение.) Возможно, Ruby использует его для реализации Matrix методов. Может ли читатель объяснить, почему существует этот недокументированный закрытый метод?

Если вы хотите использовать этот метод частного экземпляра, вы можете сделать, как предлагает @tadman.

Мой совет — использовать Matrix#. построить. (Я переименовал setMatrix в set_matrix, чтобы соответствовать соглашению Ruby по именованию методов и переменных.)

class Member
  def set_matrix(a, i, l)
    Matrix.build(6) do |r,c|
      case [r,c].sort
      when [0,0], [3,3] then a*l**2/i
      when [0,3]        then -a*l**2/i
      when [1,1], [4,4] then 12
      when [1,4]        then -12
      when [1,2], [1,5] then 6*l
      when [2,4], [4,5] then -6*l
      when [2,2], [5,5] then 4*l**2
      when [2,5]        then 2*l**2
      else              0
      end
    end
  end

  def initialize(a, i, l)
    @area = a
    @i = i
    @length = l
    @k = set_matrix(a, i, l)
  end
end

m = Member.new(1,2,3).instance_variable_get(:@k)
  #=> Matrix[[ 4,   0,   0, -5,   0,   0], 
  #          [ 0,  12,  18,  0, -12,  18],
  #          [ 0,  18,  36,  0, -18,  18],
  #          [-5,   0,   0,  4,   0,   0],
  #          [ 0, -12, -18,  0,  12, -18],
  #          [ 0,  18,  18,  0, -18,  36]]
person Cary Swoveland    schedule 21.04.2016
comment
Действительно удивительно. Ни []=, ни его псевдонимы set_element и set_component внутри класса не используются. - person Stefan; 21.04.2016
comment
Матрица симметрична, поэтому вы можете удалить некоторые избыточные пары r,c/c,r из ваших when, используя case [r,c].sort. В этом случае я бы также использовал более компактную форму when ... then. - person Stefan; 21.04.2016
comment
@Стефан, я не заметил, что он симметричен. Я включил ваше (умное) предложение. Спасибо. Можете ли вы объяснить Unbound в Matrix.instance_method(:[]=) #=> #<UnboundMethod: Matrix#[]=>, учитывая, что нет необходимости привязывать метод к матричному объекту? - person Cary Swoveland; 21.04.2016
comment
Это Unbound только потому, что у вас нет экземпляра. String.instance_method(:upcase) возвращает UnboundMethod, тогда как 'foo'.method(:upcase) возвращает (привязанное) Method. - person Stefan; 22.04.2016