何时在Ruby中使用Struct而不是Hash?

TK.*_*TK. 67 ruby hash struct

我没有太多的编程经验.但是,对我而言,Struct似乎与Hash有些相似.

  • Struct能做什么?
  • 结构可以做什么,哈希不能做什么?

在谷歌搜索之后,结构的概念在C中很重要,但我对C不太了解.

sep*_*p2k 90

结构与以下方式使用散列图不同(除了代码的外观):

  • 结构具有一组固定的属性,同时向哈希添加新键.
  • 调用结构实例上不存在的属性将导致NoMethodError,而从散列获取不存在的键的值将返回nil.
  • 即使结构具有相同的属性且实例具有相同的值(即为Struct.new(:x).new(42) == Struct.new(:x).new(42)假,但Foo = Struct.new(:x); Foo.new(42)==Foo.new(42)为真),不同结构的两个实例将永远不会相等.
  • to_astruct 的方法返回一个值数组,而to_a在hash上获取一个键值对数组(其中"pair"表示"双元素数组")
  • 如果Foo = Struct.new(:x, :y, :z)你可以Foo.new(1,2,3)创建一个实例Foo而不必拼出属性名称.

所以回答这个问题:当你想用一组已知属性建模对象时,使用结构.当您想要模拟任意使用的哈希映射时(例如,计算每个单词在字符串中出现的频率或将昵称映射到全名等等)绝对不是结构的作业,而对具有名称,年龄和地址的人进行建模时非常适合Person = Struct.new(name, age, address)).

作为旁注:C结构与红宝石结构几乎没有任何关系,所以不要让自己感到困惑.


Quv*_*Quv 43

我知道这个问题几乎得到了很好的回答,但令人惊讶的是,没有人谈到过最大的差异之一和真正的好处Struct.我猜这就是为什么有人还在问.

我理解这些差异,但是当哈希可以做同样的事情并且更容易处理时,使用结构优于哈希的真正优势是什么?看起来像Structs有点多余.

Struct更快的.

require 'benchmark'

Benchmark.bm 10 do |bench|
  bench.report "Hash: " do
    50_000_000.times do { name: "John Smith", age: 45 } end
  end

  bench.report "Struct: " do
    klass = Struct.new(:name, :age)
    50_000_000.times do klass.new("John Smith", 45) end
  end

end

# ruby 2.2.2p95 (2015-04-13 revision 50295) [x64-mingw32].
#                 user     system      total        real
# Hash:       22.340000   0.016000  22.356000 ( 24.260674)
# Struct:     12.979000   0.000000  12.979000 ( 14.095455)

# ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin11.0]
# 
#                  user     system      total        real
# Hash:       31.980000   0.060000  32.040000 ( 32.039914)
# Struct:     16.880000   0.010000  16.890000 ( 16.886061)
Run Code Online (Sandbox Code Playgroud)

  • 也许这很有趣:我用Cygwin Ruby(2.2.3p173)重新运行你的基准测试,并为用户提供了62.462的Hash和19.875.然后我在JVM 1.7上使用JRuby 1.7.23重新运行它,得到哈希的8.401和结构的8.701.虽然Ruby的速度优势很大,但在JRuby下它们似乎都有相同的速度. (3认同)

Jon*_*Jon 11

另一个主要区别是您可以向Struct添加行为方法.

 Customer = Struct.new(:name, :address) do

  def greeting; "Hello #{name}!" ; end

end

Customer.new("Dave", "123 Main").greeting  # => "Hello Dave!"
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个巨大的差异,可以证明结构与哈希的合理性。由于按照 Rails 约定,您不应该在同一个 ruby​​ 文件中拥有两个类(因为自动加载问题),因此很多时候,Struct 是创建充当演示者/装饰器的类替换的好方法。 (2认同)

Mar*_*off 10

Struct文档中:

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

另一方面,哈希:

哈希是键值对的集合.它类似于Array,除了索引是通过任何对象类型的任意键完成的,而不是整数索引.通过键或值遍历散列的顺序可能看起来是任意的,通常不会按插入顺序排列.

主要区别在于您访问数据的方式.

ruby-1.9.1-p378 > Point = Struct.new(:x, :y)
 => Point 
ruby-1.9.1-p378 > p = Point.new(4,5)
 => #<struct Point x=4, y=5> 
ruby-1.9.1-p378 > p.x
 => 4 
ruby-1.9.1-p378 > p.y
 => 5 
ruby-1.9.1-p378 > p = {:x => 4, :y => 5}
 => {:x=>4, :y=>5} 
ruby-1.9.1-p378 > p.x
NoMethodError: undefined method `x' for {:x=>4, :y=>5}:Hash
    from (irb):7
    from /Users/mr/.rvm/rubies/ruby-1.9.1-p378/bin/irb:17:in `<main>'
ruby-1.9.1-p378 > p[:x]
 => 4 
ruby-1.9.1-p378 > p[:y]
 => 5 
Run Code Online (Sandbox Code Playgroud)

简而言之,当你想要一个"普通旧数据"结构的类(可选择使用更多方法扩展它的目的)时,你会创建一个新的Struct ,并且当你不需要正式类型时你会使用Hash一点都不