Ruby类与结构

rsh*_*tty 26 ruby

我已经看到使用Structs的代码库来包装类中的属性和行为.Ruby类和Struct有什么区别?何时应该使用另一个.?

lcg*_*ida 25

来自Struct文档:

Struct是一种使用访问器方法将多个属性捆绑在一起的便捷方式,而无需编写显式类.

Struct类生成包含一组成员及其值的新子类.对于每个成员,创建类似于Module#attr_accessor的reader和writer方法.

所以,如果我想要一个Person可以访问name属性(读写)的类,我可以通过声明一个类来实现:

class Person
  attr_accessor :name

  def initalize(name)
    @name = name
  end
end
Run Code Online (Sandbox Code Playgroud)

或使用Struct:

Person = Struct.new(:name)
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,我都可以运行以下代码:

 person = Person.new
 person.name = "Name"
 #or Person.new("Name")
 puts person.name
Run Code Online (Sandbox Code Playgroud)

何时使用?

正如描述所述,当我们需要一组可访问的属性而不必编写显式类时,我们使用Structs.

例如,我想要一个点变量来保存X和Y值:

point = Struct.new(:x, :y).new(20,30)
point.x #=> 20
Run Code Online (Sandbox Code Playgroud)

更多例子:

  • 确实如此,当两者都做同样的事情时。为什么我们既有类又有结构。我的论点是何时在应用程序中使用类以及何时使用结构。它们适合哪些用例? (2认同)
  • "为什么我们同时拥有阶级和结构" - 我不明白你的意思.`Struct`是一个生成类的类.只是为了节省您的打字. (2认同)
  • 对我来说,这听起来很奇怪:“当我们需要一组可访问的属性而不必编写显式类时,我们会使用 Structs。” 这导致必须编写显式结构。显式结构与显式类? (2认同)

mes*_*ens 6

要添加到其他答案中,有些事情你不能用 Struct 做,有些事情你可以。

例如,您不能创建没有参数的 Struct

Bar = Struct.new
=> ArgumentError: wrong number of arguments (given 0, expected 1+)

Bar = Struct.new(:bar)
bar = Bar.new(nil)
bar.class
=> Bar
Run Code Online (Sandbox Code Playgroud)

但是,一个类可以让你这样做:

class Foo; end
foo = Foo.new
foo.class
=> Foo
Run Code Online (Sandbox Code Playgroud)

您不能为 Struct 参数设置默认值

Bar = Struct.new(bar: 'default')
=> ArgumentError: unknown keyword: bar

Bar = Struct.new(bar = 'default')
=> NameError: identifier default needs to be constant
Run Code Online (Sandbox Code Playgroud)

但是你可以用一个类来做,要么传递一个散列,要么参数可以按任何顺序排列,甚至丢失:

class Bar
  attr_reader :bar, :rab
  def initialize(bar: 'default', rab:)
    @bar = bar
    @rab = rab
  end
end

bar = Bar.new(rab: 'mandatory')
bar.rab
=> 'mandatory'
bar.bar
=> 'default'

bar = Bar.new(rab: 'mandatory', bar: 'custom_value')
bar.rab
=> 'mandatory'
bar.bar
=> 'custom_value'
Run Code Online (Sandbox Code Playgroud)

或者直接传递值,如果参数应该以相同的顺序给出,默认的总是在最后:

class Bar
  attr_reader :rab, :bar
  def initialize(rab, bar = 'default')
    @rab = rab
    @bar = bar
  end
end

bar = Bar.new('mandatory')
bar.rab
=> 'mandatory'
bar.bar
=> 'default'

bar = Bar.new('mandatory', 'custom_value')
bar.rab
=> 'mandatory'
bar.bar
=> 'custom_value'
Run Code Online (Sandbox Code Playgroud)

你不能用 Structs 做任何事情,除非你以这种超级冗长的方式为你的参数设置默认值:

A = Struct.new(:a, :b, :c) do
  def initialize(a:, b: 2, c: 3)
    super(a, b, c)
  end
end
Run Code Online (Sandbox Code Playgroud)

(示例取自这个答案

您可以在 Struct 中定义方法

Foo = Struct.new(:foo) do
  def method(argument)
    # do something with argument
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

结构对于创建数据对象很有用,就像其中一个答案中提到的点示例一样。

我有时会使用它们以简单的方式在测试中创建假货和模拟。有时 RSpecallow(foo).to receive(:blah)等会变得有点冗长,使用 Struct 非常简单。


小智 5

Struct 是用于创建类的 Ruby 简写。在适用的情况下使用 Struct 可以简化您的代码。在https://www.rubytapas.com/2012/11/07/episode-020-struct/ 上有一个很好的讨论

  • 欢迎使用堆栈溢出!虽然这在理论上可以回答这个问题,但 [最好](​​//meta.stackoverflow.com/q/8259) 在此处包含答案的基本部分,并提供链接以供参考。 (3认同)