美文网首页
Struct && OpenStruct

Struct && OpenStruct

作者: waynedeng | 来源:发表于2016-12-03 23:22 被阅读33次

    一、需求

    最近在做数据同步的应用,需要弄一个配置文件app.yml来进行应用的设置,例如:

    work_type: target
    config:
      name: bj-projects
      tables:
        - projects.employees
        - info.cities
    

    读取出来很简单:

    yml_file = 'config/app.yml'
    configs = ActiveSupport::HashWithIndifferentAccess.new(YAML.load(IO.read(yml_file)))
    
    # => {"work_type"=>"target", "config"=>{"name"=>"bj-projects", "tables"=>["projects.employees", "info.cities"]}}
    

    使用的时候是这样的调用方式:

    configs[:work_type], configs[:source][:config]
    

    这种Hash的方式觉得很别扭,为什么不可以用这样的方式呢?

    Config.work_type, Config.source
    

    于是便发现了Struct和OpenStruct对象。

    二、Struct类

    Struct在 Ruby 中是用纯 C语言来实现的, 用于快速声明一个 Class, 例如:

    dog = Struct.new("Dog", :name, :age)
    fred = dog.new("fred", 5)
    fred.age=6
    printf "name:%s age:%d", fred.name, fred.age
    

    等于你可以用Struct来迅速定义一个具有固定的属性的对象,在我的需求里面可以这样来解决:

    configs = Struct.new('Config', :work_type, :source)
    Config = configs.new(....)
    

    感觉还是有点繁琐,不那么智能,而且对于没有一开始指定的属性,就不能使用了,例如:

    Config.name  #会报错
    

    三、OpenStruct类

    于是今天的主角OpenStruct需要亮相了。

    An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their accompanying values. This is accomplished by using Ruby’s metaprogramming to define methods on the class itself.

    OpenStruct是一个类似于Hash的数据结构,它可以允许定义任意的具有赋值的属性。

    require 'ostruct'
    
    person = OpenStruct.new
    person.name    = "John Smith"
    person.age     = 70
    person.pension = 300
    
    puts person.name     # -> "John Smith"
    puts person.age      # -> 70
    puts person.address  # -> nil
    

    很神奇的地方,就是你可以随意指定它的属性,一旦赋值这个属性方法就存在了。

    另外一个很方便的定义方法,即通过Hash来进行定义:

    australia = OpenStruct.new(:country => "Australia", :population => 20_000_000)
    p australia   # -> <OpenStruct country="Australia" population=20000000>
    

    直接把Hash中的键值转换为类的属性。这就是我们需要的方法了。

    yml_file = 'config/app.yml'
    configs = ActiveSupport::HashWithIndifferentAccess.new(YAML.load(IO.read(yml_file)))
    Config = OpenStruct.new(configs)
    
    Config.work_type # => target
    Config.source # => {name: ....}
    # 然后还可以随意自行添加方法
    Config.name  = Config.source['name']
    

    相关文章

      网友评论

          本文标题:Struct && OpenStruct

          本文链接:https://www.haomeiwen.com/subject/lnwqmttx.html