【问题标题】:How do you call class method from initialize method?你如何从初始化方法调用类方法?
【发布时间】:2016-08-13 22:43:29
【问题描述】:

我试图在初始化方法期间调用类中的方法。这是不允许的吗?我最初有类之外的方法来尝试将其用作全局方法。当前方法试图返回创建的矩阵,然后初始化方法将返回的矩阵保存到实例变量中。

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 而不是返回矩阵,这会产生类似的错误。我还能做些什么来实现我想要的?

【问题讨论】:

  • “你说“做这个”会返回这个错误......” 大概,“这个”包括创建Member 的实例(例如,Member.new(1,2,3)),它没有显示。

标签: ruby class matrix object-initializers


【解决方案1】:

没有什么可以阻止您调用 initialize 中的方法,那里没有特殊行为,但您在这里调用的是另一个类中的 private 方法。

我不知道为什么设置为private,而且有些人观察到that seems to be a problem,所以你总是可以暴力破解它:

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

这看起来很混乱,按照该帖子中的建议进行修补可能有助于简化事情:

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

您还可以将Matrix 子类化为MutableMatrix 并包含该方法。

请注意,Ruby 的方法命名约定是 underscore_style 并且在末尾包含显式 return 不是必需的,这是隐含的。 m 一个人就可以完成这项工作。

【讨论】:

  • 另外,你应该raise ArgumentError if row &gt;= row_count || column &gt;= column_count确保rowcolumn在矩阵内。
【解决方案2】:

让我们了解更多信息:

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

后者让我很惊讶。考虑到Matrix 对象是不可变的,应该没有:[]= 方法。 (它类似于2=4,当然会引发异常。)也许Ruby 使用它来实现Matrix 方法。读者能否解释一下为什么存在这种未记录的私有方法?

如果您想使用该私有实例方法,您可以按照@tadman 的建议进行操作。

我的建议是使用Matrix#build。 (我已将 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]]

【讨论】:

  • 确实令人惊讶。在类中既不使用[]=,也不使用其别名set_elementset_component
  • 矩阵是对称的,因此您可以使用case [r,c].sortwhens 中删除一些冗余的r、c/c、r 对。在这种情况下,我还会使用更紧凑的 when ... then 表单。
  • @Stefan,我没有注意到它是对称的。我采纳了你的(聪明的)建议。谢谢。考虑到不需要将方法绑定到矩阵对象,您能解释一下Matrix.instance_method(:[]=) #=&gt; #&lt;UnboundMethod: Matrix#[]=&gt; 中的“未绑定”吗?
  • 它是“未绑定”,只是因为您没有实例。 String.instance_method(:upcase) 返回一个UnboundMethod,而'foo'.method(:upcase) 返回一个(绑定)Method
猜你喜欢
  • 1970-01-01
  • 2020-02-05
  • 2018-11-30
  • 2022-01-17
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 2011-04-01
相关资源
最近更新 更多