2016-04-21 109 views
1

我想在初始化方法中調用類中的方法。這是不允許的?我最初在課堂外有方法嘗試並將其用作全局方法。當前方法試圖返回創建的矩陣,然後initialize方法將返回的矩陣保存到實例變量中。如何從初始化方法調用類方法?

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,而不是返回矩陣,並給出了類似的錯誤。我還可以做什麼來實現我想要的?

+0

「你說:‘做這個’返回該錯誤......」據推測,「這個「包括創建'Member'的實例(例如,'Member.new(1,2,3)'),其未示出。 –

回答

6

沒有什麼可以阻止您撥打initialize中的方法,這裏沒有特別的行爲,但您在此調用的是另一個類中的私人方法。

我不知道爲什麼它的設置private,有的人已經觀察到that seems to be a problem,這樣你就可以永遠只是蠻力它:

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

這似乎亂了,修補它作爲該職位推薦可能有助於簡化事情:

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

你也可以繼承MatrixMutableMatrix和包括方法。

作爲一個說明,Ruby的方法命名約定是underscore_style,並且在末尾包括一個明確的return並不是必需的,這是隱含的。只有m才能完成這項工作。

+1

另外,如果row> = row_count ||則應該引發ArgumentError。 column> = column_count'以確保'row'和'column'在矩陣內。 – Stefan

1

讓我們獲得更多的信息:

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

後者是一個讓我吃驚。考慮到Matrix對象是不可變的,應該沒有:[]=方法。 (類似於2=4,這當然會引發異常。)Ruby可能會使用它來實現Matrix方法。讀者可以解釋爲什麼這種無證的私人方法存在嗎?

如果您希望使用該私有實例方法,您可以按照@tadman的建議進行操作。

我的建議是使用Matrix#build。 (我已經改名爲setMatrixset_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]] 
+0

確實令人驚訝。在類中不使用[] =',而使用別名'set_element'和'set_component'。 – Stefan

+0

矩陣是對稱的,所以你可以用'case [r,c] .sort'從'when's中刪除一些冗餘的r,c/c,r-對。在這種情況下,我還會使用更緊湊的'when ... then'形式。 – Stefan

+0

@Stefan,我沒有注意到它是對稱的。我結合了你的(聰明的)建議。謝謝。考慮到沒有必要將方法綁定到矩陣對象,你能解釋一下'Matrix.instance_method(:[] =)#=>#'中的'Unbound'嗎? –