How do you call class method from initialize method?

Refresh

December 2018

Views

1.9k time

1

I'm trying to call a method in a class during its initialize method. Is this not allowed? I originally had the method outside of the class to try and use it as a global method. The current method is trying to return the created matrix and then the initialize method saves the returned matrix into an instance variable.

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

Doing this returns this error

`'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>'`

I would like it to make an instance variable of a matrix when the class is instantiated. I've also tried to have the setMatrix method save the matrix to @k directly instead of returning the matrix and that gave a similar error. How else can I do to achieve what I want?

2 answers

1

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

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]]
6

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

Я не знаю , почему он установлен 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в одиночку будет делать эту работу.