我没有太多的编程经验,但对我来说,Struct似乎与Hash有些相似。
- Struct能做什么?
- Struct有什么功能是Hash无法做到的?
通过谷歌搜索,我了解到在C语言中,Struct的概念非常重要,但是我对C语言知之甚少。
结构体与哈希映射的区别如下(除代码外):
Struct.new(:x).new(42) == Struct.new(:x).new(42)
返回false,而 Foo = Struct.new(:x); Foo.new(42)==Foo.new(42)
返回true)。to_a
方法返回值数组,而哈希映射的to_a
方法返回键值对的数组(其中“pair”表示“双元素数组”)Foo = Struct.new(:x, :y, :z)
,则可以使用Foo.new(1,2,3)
创建一个Foo
实例,而不必拼写属性名称。因此,回答问题:当您想要建模具有已知属性集的对象时,请使用结构体。当您想要建模任意对象时,请使用哈希映射(例如,统计字符串中每个单词出现的次数或将昵称映射到全名等绝对不适合结构体,而使用结构体可以很好地建模具有名称、年龄和地址的人)。
顺便说一下:C语言中的结构体与Ruby中的结构体几乎没有关系,所以不要让自己被这些搞混了。
我知道这个问题差不多已经有很好的答案了,但令人惊讶的是没有人谈论过Struct
的最大区别和真正的优势。我猜这就是为什么有人仍在问的原因。
我理解它们之间的区别,但相比Hash,使用Struct的真正优势是什么?Hash也能做到同样的事情,并且更简单易用。看起来Struct似乎有些多余。
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)
ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
,我得到了相反的结果。哈希表:6.5 / 结构体:10.8
- Rein Avila另一个主要区别是您可以向结构添加行为方法。
Customer = Struct.new(:name, :address) do
def greeting
"Hello #{name}!"
end
end
Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"
从Struct文档中可知:
结构体是一种方便的方式,可以使用访问器方法将多个属性捆绑在一起,而不必编写显式类。
另一方面,Hash:
哈希是键值对的集合。它类似于数组,但索引是通过任何对象类型的任意键进行的,而不是整数索引。通过键或值遍历哈希的顺序似乎是任意的,并且通常不会按照插入顺序排序。
主要区别在于如何访问数据。
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
如果你只是要封装数据,那么哈希表(或哈希表数组)就可以了。如果你计划让数据与其他数据进行操作或交互,那么结构体可以打开一些有趣的可能性:
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
class Point << Hash
,这样所有的东西都会有点类似。 - Nakilon
Struct#==
的工作方式与您解释的不同,当您将Struct.new
的结果存储为变量时,与使用相同参数两次调用它时也会不同。 - Mark Rushakoffto_a
方法是否保证始终返回与初始定义的结构体完全相同顺序的值数组?例如,给定Foo = Struct.new(:z, :a, :b)
,我可以依赖于Foo.new(1, 2, 3).to_a[0] == 1
吗?具体来说,我可以依赖于to_a[0]
始终是:z
的值吗? - igrekstruct = Struct.new(:name, :age)
那么我仍然可以通过struct[variable]
访问属性。 - 3limin4t0r