跳到内容

继承

Object(层次结构的根节点)之外的所有类都继承自另一个类(其超类)。如果您没有指定超类,则默认情况下类继承自 Reference,结构体继承自 Struct

一个类继承了超类中的所有实例变量,以及所有实例和类方法,包括其构造函数 (newinitialize)。

class Person
  def initialize(@name : String)
  end

  def greet
    puts "Hi, I'm #{@name}"
  end
end

class Employee < Person
end

employee = Employee.new "John"
employee.greet # "Hi, I'm John"

如果一个类定义了 newinitialize,则不会继承其超类的构造函数

class Person
  def initialize(@name : String)
  end
end

class Employee < Person
  def initialize(@name : String, @company_name : String)
  end
end

Employee.new "John", "Acme" # OK
Employee.new "Peter"        # Error: wrong number of arguments for 'Employee:Class#new' (1 for 2)

您可以在派生类中覆盖方法

class Person
  def greet(msg)
    puts "Hi, #{msg}"
  end
end

class Employee < Person
  def greet(msg)
    puts "Hello, #{msg}"
  end
end

p = Person.new
p.greet "everyone" # "Hi, everyone"

e = Employee.new
e.greet "everyone" # "Hello, everyone"

您可以使用类型限制来定义专门的方法,而不是覆盖方法

class Person
  def greet(msg)
    puts "Hi, #{msg}"
  end
end

class Employee < Person
  def greet(msg : Int32)
    puts "Hi, this is a number: #{msg}"
  end
end

e = Employee.new
e.greet "everyone" # "Hi, everyone"

e.greet 1 # "Hi, this is a number: 1"

super

您可以使用 super 调用超类的方法

class Person
  def greet(msg)
    puts "Hello, #{msg}"
  end
end

class Employee < Person
  def greet(msg)
    super # Same as: super(msg)
    super("another message")
  end
end

没有参数或括号时,super 会接收方法的所有参数作为参数。否则,它会接收您传递给它的参数。

协变和逆变

继承在数组方面可能会有点棘手。我们在声明一个使用继承的对象数组时,必须小心。例如,考虑以下情况

class Foo
end

class Bar < Foo
end

foo_arr = [Bar.new] of Foo  # => [#<Bar:0x10215bfe0>] : Array(Foo)
bar_arr = [Bar.new]         # => [#<Bar:0x10215bfd0>] : Array(Bar)
bar_arr2 = [Foo.new] of Bar # compiler error

Foo 数组可以同时容纳 Foo 和 Bar,但 Bar 数组只能容纳 Bar 及其子类。

自动转换可能会让您在某些情况下感到困惑。例如,以下代码无法正常运行

class Foo
end

class Bar < Foo
end

class Test
  @arr : Array(Foo)

  def initialize
    @arr = [Bar.new]
  end
end

我们已将 @arr 声明为 Array(Foo) 类型,因此我们可能会认为可以开始在其中放入 Bar。并非完全如此。在 initialize 中,[Bar.new] 表达式的类型始终为 Array(Bar)。而 Array(Bar) 无法 赋值给 Array(Foo) 实例变量。

正确的做法是什么?更改表达式以使其具有正确的类型:Array(Foo)(参见上面的示例)。

class Foo
end

class Bar < Foo
end

class Test
  @arr : Array(Foo)

  def initialize
    @arr = [Bar.new] of Foo
  end
end

这仅仅是一个类型(Array)和一个操作(赋值),上述逻辑将在其他类型和赋值中以不同的方式应用,总的来说,协变和逆变 没有得到完全支持。