Crystal:继承 vs 包含 vs 扩展 类继承模块包含模块扩展

问题描述

我在 In Crystal,what's the difference between inheritance and inclusion? 提出了这个问题的更有限版本,但我认为我(和其他读者)会从更全面的答案中受益。

继承(带有<)、包含(带有include)和扩展之间有什么区别>(使用 extend)在 Crystal 类中?

解决方法

答案

类继承

带有 < 的继承将实例属性、实例方法、类属性和类方法从继承的复制到当前类中。

模块不能继承或被继承。

class A
  # Equivalent to `@@foo = 1` with corresponding getter and setter class methods
  @@foo = 1

  # Equivalent to `@foo = ` with corresponding getter and setter instance methods
  @foo = 2
end

class B < A
end

pp A.foo == B.foo  # true
pp A.new.foo == B.new.foo  # true

超类中类属性的值与子类中的值不同,但类型相同。

class C
  class_property foo = 1
end

class D < C
end

D.foo = 9
pp C.foo == D.foo  # false

一个类只能从一个类继承。

模块包含

include 将包含的模块中的实例属性和实例方法复制到当前类或模块中。

不能包含类。

可以在模块上定义类属性和类方法,但是这些不会通过包含而重复;他们被忽略了。

module BirdHolder
  # Ignored by `include`
  class_property bird = "123"
  property bird = "456"
end

class Thing
  include BirdHolder
end

pp Thing.new.bird  # "456"
pp Thing.bird  # Error: undefined method 'bird' for Thing1.class

一个类型(模块或类)可以包含任意数量的模块。

模块扩展

extend 将包含的模块中的实例方法复制到当前类或模块中,但作为类方法。

不能扩展类。

来自扩展模块的类属性和类方法被忽略。

module Talkative
  # Ignored by `extend`
  @@stuff = "zxcv"

  # Ignored by `extend`
  def self.say_stuff
    puts "stuff"
  end

  def say_stuff
    puts @@stuff
  end
end

class Thing
  extend Talkative
  @@stuff = "asdf"
end

Thing.say_stuff  # "asdf"

注意@@stuff模块定义中的Talkative指的是扩展类的class属性,而不是Talkative本身的class属性.

无法扩展定义实例方法的模块。这会导致编译错误。

一个类型(模块或类)只能扩展一个模块。

参考文献

此信息基于:

此答案自 Crystal 1.0.0 起有效