什么时候在Ruby中使用Struct而不是Hash?

我没有太多的编程经验。 但是,对我来说,Struct看起来有些类似于Hash。

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

用Googlesearch后,Struct的概念在C中很重要,但我对C的了解不多。

结构不同于以下方式使用hashmaps(除了代码的外观):

  • 一个结构有一组固定的属性,而你将新的键添加到散列。
  • 调用结构实例上不存在的属性将导致NoMethodError,而从散列中获取不存在的键的值将仅返回nil。
  • 即使结构具有相同的属性并且实例具有相同的值(即Struct.new(:x).new(42) == Struct.new(:x).new(42)两个不同结构的实例也不会相同。 Struct.new(:x).new(42) == Struct.new(:x).new(42)为假,而Foo = Struct.new(:x); Foo.new(42)==Foo.new(42)为真)。
  • to_a方法返回一个值的数组,而to_a上的to_a得到一个键 – 值对的数组(其中“pair”表示“二元数组”)
  • 如果Foo = Struct.new(:x, :y, :z) ,则可以执行Foo.new(1,2,3)来创buildFoo的实例,而不必拼出属性名称。

所以要回答这个问题:当你想用一组已知属性来build模对象时,使用结构体。 当你想build模任意使用hashmaps(例如计算每个单词出现在string中的频率或映射昵称到全名等肯定不是一个结构的工作,而build模一个人的名字,年龄和地址将是Person = Struct.new(name, age, address)的完美契合)。

作为一个注释:C结构与ruby结构没有多大关系,所以不要让自己被这个混淆。

我知道这个问题已经得到了很好的回答,但是令人惊讶的是没有人谈到Struct最大的区别和真正的好处之一。 我想这就是为什么有人还在问 。

我明白不同之处,但是在Hash上使用Struct,Hash可以做同样的事情,而且处理更简单,真正的优点是什么? 看起来像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) 

从Struct文档:

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

另一方面, 哈希 :

哈希是键值对的集合。 它类似于一个数组,除了索引是通过任意对象types的任意键来完成的,而不是一个整数索引。 您通过键或值遍历散列的顺序可能看起来是任意的,并且通常不会处于插入顺序中。

主要的区别是你如何访问你的数据。

 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 > px => 4 ruby-1.9.1-p378 > py => 5 ruby-1.9.1-p378 > p = {:x => 4, :y => 5} => {:x=>4, :y=>5} ruby-1.9.1-p378 > px 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 

简而言之,当你想要一个“简单的旧数据”结构的类 (可select用更多方法扩展它的意图)时,你会创build一个新的结构,而当你不需要一个正式的types在所有。

另一个主要区别是你可以添加行为方法到一个结构。

  Customer = Struct.new(:name, :address) do def greeting; "Hello #{name}!" ; end end Customer.new("Dave", "123 Main").greeting # => "Hello Dave!" 

如果你只是要封装数据,那么一个哈希(或一个哈希数组)是好的。 如果您打算让数据操作或与其他数据交互,那么Struct可以打开一些有趣的可能性:

 Point = Struct.new(:x, :y) point_a = Point.new(0,0) point_b = Point.new(2,3) class Point def distance_to another_point Math.sqrt((self.x - another_point.x)**2 + (self.y - another_point.y)**2) end end puts point_a.distance_to point_b