什么是红宝石偏类?

时间:2014-07-27 06:43:05

标签: ruby

我读到下面的代码片段实现了所谓的 partial class

class A
  def a
    puts 'a'
  end
end

class B < A
  def ba1
    puts 'ba1'
  end
end

class A
  def b
    puts 'b'
  end
end

class B < A
  def ba2
    puts 'ba2'
  end
end

ob = B.new
ob.a
ob.b
ob.ba1
ob.ba2

从两个类B扩展了两个类A。我不明白红宝石如何知道A B的延伸范围。在创建B的实例时,ruby如何知道它是B?执行结果是:

a
b
ba1
ba2

初始化的B是两个B类的实例。有人可以解释一下吗?

5 个答案:

答案 0 :(得分:7)

当您在Ruby中编写一个已经声明的类时,您不会覆盖该类,而是 patch 它。

这意味着ruby不会忘记旧的定义,而是添加它。

只有一个B类 - 它是两个class B块中的复合代码。

例如:

class A
  def a
    puts 'a'
  end
end

a = A.new
a.public_methods(false)
# => [:a]

class A
  def b
    puts 'b'
  end
end

a.public_methods(false)
# => [:a, :b]

在此示例中,在创建A的实例之后,类a已更改,但正如您所见,它知道添加了一个新方法(public_methods列出了实例的可用方法。

有些事情你不能做,例如 - 改变一个类的父类。如果我们尝试采用上面的代码,并声明另一个块:

class A < String
  def c
    puts 'c'
  end
end
# TypeError: superclass mismatch for class A

你得到一个错误,说你正在尝试更改基类,这是不可能的(如果在初始声明中没有继承声明,则该类隐式继承自Object

答案 1 :(得分:5)

唯一的B类,继承自A。诀窍是你可以在不同的地方自由声明B(显然,这允许你 monkeypatch 现有的类。)

编写class B < A后,如果尚未定义B类,则会打开现有的B进行扩展,或者正在创建新的{{1}}。

希望它有所帮助。

答案 2 :(得分:3)

没有&#34;部分课程&#34;在Ruby中。部分类是C#的一个特性,而不是Ruby。

在Ruby中,类定义表达式将在类的上下文中执行它内部的任何内容。你可以拥有任意数量的类声明表达式,但这并不重要。这允许您分段定义您的类,即使在不同的文件中,甚至在不同的库中也是如此。它还允许某人 else 稍后(重新)定义您的班级。

在Python中,这被称为&#34;猴子修补&#34;并且经常不赞成,Ruby社区已经采用了这个术语,但具有中性意义,因为,实际上,在Ruby中所有类定义都是猴子修补!

那么,你上面会有什么

  1. 如果A已存在,则修改A的课程定义,如果不存在,则修改新课程。
  2. 如果B已存在,则修改B的班级定义,如果不存在则修改新班级。 (B是否已经存在但是具有不同于A的超类,这会引发TypeError "superclass mismatch"。)
  3. 修改A的类定义(因为A已定义)。
  4. 修改B的类定义(因为B已经定义)。我们本可以省略超类,在这种情况下,我们会假设现有的超级类B(即A)。
  5. 顺便说一下:从技术上讲,AB不是课程。它们是引用到类的变量(更准确地说,常量)。类是对象,它们可以被变量引用,作为参数传递给方法,从方法等返回。

    此外,超类声明不必是常量,它可以是任意Ruby表达式:

    class Foo < if rand < 0.5 then String else Array end
    end
    

    完全有效(并且完全没用;-))

    class Foo < Bar; end
    
    def qux(sym); const_get(sym) end
    
    class Foo < qux(:Bar); end
    

    也是完全有效的,不会产生超类不匹配,因为常量Bar和方法调用qux(:Bar)都返回相同的对象(这是一个类)。

答案 3 :(得分:1)

可以重新定义Ruby类定义。第二个class A只是向现有类添加了新方法。第二个class B < A同样扩展了B的定义。

答案 4 :(得分:1)

# In Ruby writing

class A
  def a; puts 'a' end
end

class A
  def b; puts 'b' end
end

# is same as writing

class A
  def a; puts 'a' end
  def b; puts 'b' end
end