如何在 Ruby 中为几何形状(点、线、正方形、三角形等)创建 类

How to create classes for geometric shapes (points, lines, square, triangle, etc.) in Ruby

我们被要求通过 classes 创建几何形状。我们必须创建:

  1. 一个点class.
  2. A Line class(线 - 当两点相连时)。
  3. 一个正方形class.

我创建了一个点 class,具有可访问的坐标 (2D):

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end
  def x=(value)
    @x = value
  end
  def x()
    @x
  end
  def y=(value)
    @y = value
  end
  def y()
    @y
  end
end

而且,我想创建一个新点class:

p = Point.new
  p.x = 1
  p.y = 5
  print p # -> #<Point:0x007f9463089cc0>

因此,我有这样的事情:

#<Point:0x007f9463089cc0>

这是什么意思?

如果我print p.x, p.y那么我会得到一个可以理解的结果:

print p.x, ", ", p.y # -> 1, 5

如何在屏幕上理解这个结果?

创建点、线和几何形状在实际编程工作中有什么用吗?

您不需要编写 setter 和 getter 方法:

  def x=(value)
    @x = value
  end
  def x()
    @x
  end
  def y=(value)
    @y = value
  end
  def y()
    @y
  end

这是因为您可以使用:

attr_accessor :x, :y

并且 attr_accessor 会为您做到这一点。

您可能希望在构造函数中允许一些灵活性。您的 initialize 方法允许传递 xy 的值,如果未传递任何值,则默认为 10,因此您可以这样做:

def initialize(x = 10, y = 10)
  @x = x
  @y = y
end

这样,你会得到:

p1 = Point.new 
puts p.x # => 10
puts p.y # => 10

p2 = Point.new(15, 20)
puts p.x # => 15
puts p.y # => 20

注意 p1 我没有传递任何参数,但 xy 都按预期设置了,因为我们在方法中为它们设置了默认值定义,这里:

def initialize(x = 10, y = 10)

关于你为什么看到这个的问题:

p = Point.new
p.x = 1
p.y = 5
print p # -> #<Point:0x007f9463089cc0>

Point:0x007fa003885bf8 表示您在变量 p 中有一个 class Point 的实例。默认情况下 Ruby 将在您尝试打印对象时调用对象的 to_s 方法,因为在您的情况下您没有定义该方法,它将通过继承链查看谁定义了该方法.事实证明,该方法是在所有 Ruby 对象隐式继承自的对象 class 中找到的,并且该方法的默认行为是打印 class 的名称,后跟实例的 ID在内存中,格式为:

#<ClassName:MemoryID>

参见:http://ruby-doc.org/core-2.3.1/Object.html#method-i-to_s

如果你想改变它,那么你可以将 to_s 覆盖为这样的东西:

def to_s
  "Point #{x},#{y}"
end

这样你会得到:

puts Point.new # => "Point 10,10"

没什么问题。

#<Point:0x007f9463089cc0> 

只是表示它是classPoint的实例(#<>部分),对象ID为0x007f9463089cc0。对象 ID 是 Ruby 的解释器查找每个对象的标识符,很像内存地址。

虽然一切都很好,但 Ruby 中总有一种方法可以减少代码。例如:

class Point
  attr_accessor :x, :y

  def initialize(x = 10, y = 10)
    @x, @y = x, y
  end
end

甚至:

Point = Struct.new(:x, :y)

因为你要声明attr_accessor :x, :y 您实际上不需要为 xy 定义 getter 和 setter, 所以你的 class 可以简化为:

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end
end

你也可以添加一个to_s方法到Point:

class Point
  attr_accessor :x, :y
  def initialize
    @x = 10
    @y = 10
  end

  def to_s
     "(#{x}, #{y})"
  end
end

所以你可以使用 puts p 并在你这样做时得到输出 (10, 10):

p = Point.new
puts p
(10, 10)  

我更喜欢使用puts而不是print,因为它在输出后插入一个换行符,而且看起来更具可读性。 在 to_s 中,我正在使用 Ruby 的字符串插值 "#{}" 为您的 Point 实例构建一个不错的输出。

方法printputs输出to_s的结果,p输出inspect的结果。除非您覆盖这些方法,否则默认情况下,自定义 class 继承 Object returns 您获得的形式 #<class_name:object_id>。如果你想要一些其他的输出,覆盖这些方法,例如

class Point
  def to_s
    "#@x,#@y"
  end
end
...
print p