Ruby 技术货: 讲讲 Ruby 中纯数据结构 ( Struct 与 OpenStruct )

lyfi2003 · September 28, 2013 · Last by rails_taotao replied at April 28, 2018 · 12345 hits

我们知道在 C 与 C++ 中,拥有 struct 这种纯粹存储数据类型的写法。我们叫它 结构体.

而且,在有的时候,这种用法非常有用,例如,我们要存储一张名片,最简单的方式就是声明一个 Card 结构体:

// c code
#include <stdio.h>
struct card {                                                                   
  char *name;
  char *addr;
};

int main(){
  struct card c;
  c.name = "xxx";
  printf("card: %s\n", c.name);
  return 0;
};

有人会问,我用类就可以实现同样的功能了嘛,

# ruby code
class Card                                                                  
  attr_accessor :name, :addr
end 

c = Card.new
c.name = 'yafei lee'
puts c.name

但是,我们却忽略了很多结构体的功能:对比,快速声明,序列化。这正是 StructOpenStruct 所带给大家的. 同样的问题,我分别的用 StructOpenStruct 看下:

# ruby code
# struct
Card = Struct.new(:name, :addr)                                             

c = Card.new
c.name = 'yafei lee'
puts c.name

c2 = Card.new
c2.name = 'yafei lee'
puts c2 == c # true

OpenStruct:

# ruby code
require 'ostruct'                                                                         
Card = OpenStruct

c = Card.new
c.name = 'yafei lee'
puts c.name

c2 = Card.new
c2.name = 'yafei lee'
puts c2.name
puts c2 == c # true

可以看得出,StructOpenStruct 让声明结构体更加简单纯粹,而不需要声明一个 "冗余" 的类,加一堆属性. 除此之外,它俩都可以帮助将 ==, eql? 这些事情做好。最后还实现了 marshal_dumpmarshal_load, 满足持久化的功能:什么是 Marshal 持久化?

最后,讲一下它俩之间的区别:

来自 WinDy Blog

好分享。

用 Hash 也不错

#3 楼 @sevk hash 不够 oo

不錯,最近也有想 Ruby 中關於數據結構的問題

上次看哪个 gem 的源码碰到过,有点印象,可以深入了解下。

擦。。。我每次都去写一个不保存的数据库类。。。

非常实用的分享,赞一个。

学习一个,前几天正好遇到过 OpenStruct,正好理一下

嗯,确实不错

thx for sharing, 解释的很清楚,学习了。

@cym 这两篇质量很高,正好可以配合着看看。

#5 楼 @Martin91 #10 楼 @ghosTM55 #9 楼 @caok thx~ @sanivbyfish 这次就知道用什么了,正是你这种场合~

好文章,头球!!!

good job, 多谢分享! c 中的 Struct 比较简单,不支持方法,Struct 更像是 C++ 中的 struct

Struct , OpenStruct, Hash 各自适用场合 Use Struct if 1.you need a data container and fields are fixed and known beforehand (i.e. at time of writing of the code), 2.you need a structured Hash key, 3.you want to quickly define a class with a few fields, 4.you need to detect errors caused by misspelled field names.

Use OpenStruct if 1.the number of fields is fixed at runtime but varies frequently during development time (this is often the case for objects that should hold the result of command line option parsing), 2.you need a mock or a want to quickly have objects at hand which can be filled via usual attribute setters and getters. You might want to replaced with a proper class (or Struct) later — with explicit attribute declarations via attr_accessor and relatives.

Use Hash if 1.the number of fields is unknown at coding time, 2.there is a potentially unlimited number of fields (e.g. when reading key values from a file as is often the case for script based text processing). 原文http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html

笔记一则:

class Gear
  # 车轮的抽象数据结构
  Wheel = Struct.new(:rim, :tire)
  # 整理输入数据
  def wheelify(data)
    data.collect do |per|
      Wheel.new(per[0], per[1])
    end
  end

  attr_reader :wheels

  def initialize(data)
    @wheels = wheelify data
  end


  def diameters
    wheels.collect { |wheel| diameter wheel }
  end

  # 计算车轮直径
  def diameter(wheel)
    wheel.rim + (wheel.tire * 2)
  end
end


input = [
    [622, 20],
    [622, 23],
    [559, 30],
    [559, 40],
]
p Gear.new(input).diameters

=begin
此时的 Wheel 还没有必要单独抽出来, 用 Struct 是一个方便当下又面向未来的方法.


依赖行为而不依赖数据: 使用存取器而不是直接操作实例变量.
隐藏具体的数据结构: 将输入数据的格式处理单独封装, 将无语义的数据索引转化为有语义的属性值.
=end

好的分享。用到的机会很多,又学习一些

You need to Sign in before reply, if you don't have an account, please Sign up first.