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

时间:2021-12-15 16:24:42

I don't have much programming experience. But, to me, Struct seems somewhat similar to Hash.

我没有太多编程经验。但是,对我来说,结构似乎有点类似于散列。

  • What can Struct do well?
  • Struct能做什么?
  • Is there anything Struct can do, that Hash cannot do?
  • 有什么结构可以做的,哈希不能做的吗?

After googling, the concept of Struct is important in C, but I don't know much about C.

在google之后,Struct的概念在C中很重要,但是我对C知之甚少。

5 个解决方案

#1


79  

Structs differ from using hashmaps in the following ways (in addition to how the code looks):

结构与使用hashmap的方式不同(除了代码的外观):

  • A struct has a fixed set of attributes, while you add new keys to a hash.
  • struct有一组固定的属性,而在一个散列中添加新键。
  • Calling an attribute that does not exist on an instance of a struct will cause a NoMethodError, while getting the value for a non-existing key from a hash will just return nil.
  • 调用结构实例上不存在的属性将导致NoMethodError,而从散列中获取不存在键的值只会返回nil。
  • Two instances of different structs will never be equal even if the structs have the same attributes and the instances have the same values (i.e. Struct.new(:x).new(42) == Struct.new(:x).new(42) is false, whereas Foo = Struct.new(:x); Foo.new(42)==Foo.new(42) is true).
  • 即使结构具有相同的属性并且实例具有相同的值(例如. Struct.new(:x).new(42) = Struct.new(:x).new(x).new(:x).new(42)是假的,而Foo = Struct.new(:x);Foo.new(42)= = Foo.new(42)是正确的)。
  • The to_a method for structs returns an array of values, while to_a on a hash gets you an array of key-value-pairs (where "pair" means "two-element array")
  • 结构体的to_a方法返回一个值数组,而散列上的to_a返回一个键值对数组(其中“pair”表示“双元素数组”)
  • If Foo = Struct.new(:x, :y, :z) you can do Foo.new(1,2,3) to create an instance of Foo without having to spell out the attribute names.
  • 如果Foo =结构。new(:x,:y,:z)您可以执行Foo.new(1,2,3)来创建Foo实例,而不需要拼写属性名。

So to answer the question: When you want to model objects with a known set of attributes, use structs. When you want to model arbitrary use hashmaps (e.g. counting how often each word occurs in a string or mapping nicknames to full names etc. are definitely not jobs for a struct, while modeling a person with a name, an age and an address would be a perfect fit for Person = Struct.new(name, age, address)).

因此,要回答这个问题:当您想用一组已知的属性对对象进行建模时,请使用struct。当你想模型任意使用hashmap(例如计数频率每个单词出现在一个字符串或别名映射到全名等绝对不是就业结构,在建模一个人一个名字,一个年龄和地址将是一个完美的适合人=结构。新(姓名、年龄、地址))。

As a sidenote: C structs have little to nothing to do with ruby structs, so don't let yourself get confused by that.

作为sidenote: C structs与ruby structs几乎没有任何关系,所以不要为此感到困惑。

#2


35  

I know this question was almost well-answered, but surprisingly nobody has talked about one of the biggest differences and the real benefits of Struct. And I guess that's why somebody is still asking.

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

I understand the differences, but what's the real advantage to using a Struct over a Hash, when a Hash can do the same thing, and is simpler to deal with? Seems like Structs are kind of superfluous.

我理解它们的区别,但是当一个哈希可以做同样的事情,并且处理起来更简单时,使用结构体而不是哈希的真正好处是什么呢?似乎结构体是多余的。

Struct is faster.

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)

#3


10  

From the Struct documentation:

从结构文档:

A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.

Struct是一种方便的方法,可以使用accessor方法将许多属性捆绑在一起,而无需编写显式类。

On the other hand, a Hash:

另一方面,哈希:

A Hash is a collection of key-value pairs. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order.

哈希是键-值对的集合。它类似于数组,只是索引是通过任何对象类型的任意键完成的,而不是整数索引。按键或值遍历哈希的顺序可能看起来是任意的,而且通常不会按插入顺序。

The main difference is how you access your data.

主要的区别在于您如何访问您的数据。

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 

In short, you would make a new Struct when you want a class that's a "plain old data" structure (optionally with the intent of extending it with more methods), and you would use a Hash when you don't need a formal type at all.

简而言之,当您想要一个“简单的旧数据”结构(可以随意地用更多的方法扩展它的意图)时,您将创建一个新的Struct,而当您不需要一个正式类型时,您将使用一个散列。

#4


8  

One more main difference is you can add behavior methods to a Struct.

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

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

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

end

Customer.new("Dave", "123 Main").greeting  # => "Hello Dave!"

#5


0  

If you're just going to encapsulate the data, then a Hash (or an Array of Hashes) are fine. If you're planning to have the data manipulate or interact with other data, then a Struct can open some interesting possibilities:

如果只是封装数据,那么散列(或散列数组)就可以了。如果您计划让数据被操作或与其他数据交互,那么结构体可以打开一些有趣的可能性:

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

#1


79  

Structs differ from using hashmaps in the following ways (in addition to how the code looks):

结构与使用hashmap的方式不同(除了代码的外观):

  • A struct has a fixed set of attributes, while you add new keys to a hash.
  • struct有一组固定的属性,而在一个散列中添加新键。
  • Calling an attribute that does not exist on an instance of a struct will cause a NoMethodError, while getting the value for a non-existing key from a hash will just return nil.
  • 调用结构实例上不存在的属性将导致NoMethodError,而从散列中获取不存在键的值只会返回nil。
  • Two instances of different structs will never be equal even if the structs have the same attributes and the instances have the same values (i.e. Struct.new(:x).new(42) == Struct.new(:x).new(42) is false, whereas Foo = Struct.new(:x); Foo.new(42)==Foo.new(42) is true).
  • 即使结构具有相同的属性并且实例具有相同的值(例如. Struct.new(:x).new(42) = Struct.new(:x).new(x).new(:x).new(42)是假的,而Foo = Struct.new(:x);Foo.new(42)= = Foo.new(42)是正确的)。
  • The to_a method for structs returns an array of values, while to_a on a hash gets you an array of key-value-pairs (where "pair" means "two-element array")
  • 结构体的to_a方法返回一个值数组,而散列上的to_a返回一个键值对数组(其中“pair”表示“双元素数组”)
  • If Foo = Struct.new(:x, :y, :z) you can do Foo.new(1,2,3) to create an instance of Foo without having to spell out the attribute names.
  • 如果Foo =结构。new(:x,:y,:z)您可以执行Foo.new(1,2,3)来创建Foo实例,而不需要拼写属性名。

So to answer the question: When you want to model objects with a known set of attributes, use structs. When you want to model arbitrary use hashmaps (e.g. counting how often each word occurs in a string or mapping nicknames to full names etc. are definitely not jobs for a struct, while modeling a person with a name, an age and an address would be a perfect fit for Person = Struct.new(name, age, address)).

因此,要回答这个问题:当您想用一组已知的属性对对象进行建模时,请使用struct。当你想模型任意使用hashmap(例如计数频率每个单词出现在一个字符串或别名映射到全名等绝对不是就业结构,在建模一个人一个名字,一个年龄和地址将是一个完美的适合人=结构。新(姓名、年龄、地址))。

As a sidenote: C structs have little to nothing to do with ruby structs, so don't let yourself get confused by that.

作为sidenote: C structs与ruby structs几乎没有任何关系,所以不要为此感到困惑。

#2


35  

I know this question was almost well-answered, but surprisingly nobody has talked about one of the biggest differences and the real benefits of Struct. And I guess that's why somebody is still asking.

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

I understand the differences, but what's the real advantage to using a Struct over a Hash, when a Hash can do the same thing, and is simpler to deal with? Seems like Structs are kind of superfluous.

我理解它们的区别,但是当一个哈希可以做同样的事情,并且处理起来更简单时,使用结构体而不是哈希的真正好处是什么呢?似乎结构体是多余的。

Struct is faster.

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)

#3


10  

From the Struct documentation:

从结构文档:

A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.

Struct是一种方便的方法,可以使用accessor方法将许多属性捆绑在一起,而无需编写显式类。

On the other hand, a Hash:

另一方面,哈希:

A Hash is a collection of key-value pairs. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index. The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order.

哈希是键-值对的集合。它类似于数组,只是索引是通过任何对象类型的任意键完成的,而不是整数索引。按键或值遍历哈希的顺序可能看起来是任意的,而且通常不会按插入顺序。

The main difference is how you access your data.

主要的区别在于您如何访问您的数据。

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 

In short, you would make a new Struct when you want a class that's a "plain old data" structure (optionally with the intent of extending it with more methods), and you would use a Hash when you don't need a formal type at all.

简而言之,当您想要一个“简单的旧数据”结构(可以随意地用更多的方法扩展它的意图)时,您将创建一个新的Struct,而当您不需要一个正式类型时,您将使用一个散列。

#4


8  

One more main difference is you can add behavior methods to a Struct.

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

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

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

end

Customer.new("Dave", "123 Main").greeting  # => "Hello Dave!"

#5


0  

If you're just going to encapsulate the data, then a Hash (or an Array of Hashes) are fine. If you're planning to have the data manipulate or interact with other data, then a Struct can open some interesting possibilities:

如果只是封装数据,那么散列(或散列数组)就可以了。如果您计划让数据被操作或与其他数据交互,那么结构体可以打开一些有趣的可能性:

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