通过Struct一般用于创建具有结构化数据的类,一般方式如下

#通过Struct.new创建Customer类
#通过在块中创建方法来创建Customer类的实例方法
#对Struct.new中的属性实现了attr_accessor方法
Customer = Struct.new(:name, :address) do
  def greeting
    "Hello #{name}!"
  end
end

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

#对比Class类方式创建类
Customer = Class.new do
  def greeting
    "hello world"
  end
end

obj = Customer.new.greeting #"hello world"

通过Struct来创建类的第二种方式

#Struct.new的第一个参数是需要创建的类本身,通过Struct::类来记性类的实例化操作
Struct.new("Customer", :name, :address)
Struct::Customer.new("Dave", "123 Main")

Tip:将Struct.new的返回值赋值给常量,并像类一样使用它

代码示例中,通过hash来存储数据,对比hash和struct

require 'csv'

class Demo
  def initialize(file_name)
    @readings = []

    CSV.foreach(file_name, headers: true) do |row|
      @readings << {
        high: row[3],
        low: row[2]
      }
    end
  end

  def mean
    return 0.0 if @readings.size.zero?

    total = @readings.reduce(0.0) do |sum, reading|
      sum + (reading[:high].to_f + reading[:low].to_f)/2.0
    end

    total.to_f / @readings.size.to_f
  end
end

obj = Demo.new("/Users/jayzen/Desktop/csvs.csv")
p obj.mean

上面代码的问题罗列如下

1.在mean方法中,如果要访问hash里面的数据,需要了解hash内部的细节(即哪个键对应哪个值),因此对initiailze方法内容有详细的了解。

2.hash如果是按照hash['name']的形式来进行数据访问,这样缺少访问限制

下面的方法通过使用Struct类来进行改进。

require 'csv'

class Demo
  Reading = Struct.new(:high, :low)

  def initialize(file_name)
    @readings = []

    CSV.foreach(file_name, headers: true) do |row|
      @readings << Reading.new(row[3], row[2])
    end
  end

  def mean
    return 0.0 if @readings.size.zero?

    total = @readings.reduce(0.0) do |sum, reading|
      sum + (reading.high.to_f + reading.low.to_f)/2.0
    end

    total.to_f / @readings.size.to_f
  end
end

obj = Demo.new("/Users/jayzen/Desktop/csvs.csv")
p obj.mean

通过reading.high的形式更符合面向对象语言的使用习惯。

下面利用Struct中生成方法的方式来更新mean方法。

require 'csv'

class Demo
  Reading = Struct.new(:high, :low) do
    def mean
      (high.to_f + low.to_f) / 2.0
    end
  end

  def initialize(file_name)
    @readings = []

    CSV.foreach(file_name, headers: true) do |row|
      @readings << Reading.new(row[3], row[2])
    end
  end

  def mean_value
    total = @readings.reduce(0.0) do |sum, reading|
      sum + reading.mean
    end

    total / @readings.size.to_f
  end
end

obj = Demo.new("/Users/jayzen/Desktop/csvs.csv")
p obj.mean_value

results matching ""

    No results matching ""