如何在Ruby中使用new干净地初始化属性?

xa9qqrwz  于 2023-08-04  发布在  Ruby
关注(0)|答案(8)|浏览(171)
class Foo
  attr_accessor :name, :age, :email, :gender, :height

  def initalize params
    @name = params[:name]
    @age = params[:age]
    @email = params[:email]
    .
    .
    .
  end

字符串
这似乎是一种愚蠢的方式。在Ruby中初始化对象的更好/更惯用的方法是什么?
Ruby 1.9.3

qltillow

qltillow1#

您可以只迭代键并调用setter。我更喜欢这样,因为如果你传递一个无效的键,它会被捕获。

class Foo
  attr_accessor :name, :age, :email, :gender, :height

  def initialize params = {}
    params.each { |key, value| send "#{key}=", value }
  end
end

foo = Foo.new name: 'Josh', age: 456
foo.name  # => "Josh"
foo.age   # => 456
foo.email # => nil

字符串

zpgglvta

zpgglvta2#

def initialize(params)
  params.each do |key, value|
    instance_variable_set("@#{key}", value)
  end
end

字符串

hof1towb

hof1towb3#

为了利用约书亚·奇克的回答,用一点概括

module Initializable
  def initialize(params = {})
    params.each do |key, value|
      setter = "#{key}="
      send(setter, value) if respond_to?(setter.to_sym, false)
    end
  end
end

class Foo
  include Initializable

  attr_accessor :name, :age, :email, :gender, :height
end

Foo.new name: 'Josh', age: 456
=> #<Foo:0x007fdeac02ecb0 @name="Josh", @age=456>

字符串

NB如果初始化mix-in已经被使用 * 并且 * 我们需要自定义初始化,我们只需调用super:

class Foo
  include Initializable

  attr_accessor :name, :age, :email, :gender, :height, :handler

  def initialize(*)
    super

    self.handler = "#{self.name} #{self.age}"
  end
end

Foo.new name: 'Josh', age: 45
=> #<Foo:0x007fe94c0446f0 @name="Josh", @age=45, @handler="Josh 45">

gupuwyp2

gupuwyp24#

Foo = Struct.new(:name, :age, :email, :gender, :height)

字符串
这对于一个功能齐全的类来说已经足够了。演示:

p Foo.class # Class

employee = Foo.new("smith", 29, "smith@foo.com", "m", 1.75) #create an instance
p employee.class # Foo
p employee.methods.sort # huge list which includes name, name=, age, age= etc

rsl1atfo

rsl1atfo5#

为什么不直接明确地指定一个实际的参数列表呢?

class Foo
  attr_accessor :name, :age, :email, :gender, :height

  def initialize(name, age, email, gender, height)
    @name = name
    @age = age
    @email = email
    @gender = gender
    @height = height
  end
end

字符串
这个版本可能比其他版本的代码行多,但它使其更容易利用内置的语言特性(例如参数的默认值或在调用initialize时引发错误)。

omvjsjqw

omvjsjqw6#

使用params中的所有键是不正确的,你可以定义不愿意的名称。我觉得应该是白色名单

class Foo
   @@attributes = [:name, :age, :email, :gender, :height]  

   @@attributes.each do |attr|
     class_eval { attr_accessor "#{attr}" }
   end  

   def initialize params
     @@attributes.each do |attr|
       instance_variable_set("@#{attr}", params[attr]) if params[attr]
     end  
   end
end

Foo.new({:name => 'test'}).name #=> 'test'

字符串

yzckvree

yzckvree7#

如果你接收的是一个散列作为唯一的参数,为什么不把它作为一个示例变量呢?每当你需要一个值时,从哈希调用它。您可以保持示例变量名简短,以便可以轻松调用它。

class Foo
  attr_reader :p
  def initalize p
    @p = p
  end
  def foo
    do_something_with(@p[:name])
    ...
  end
end

字符串
如果@p[:name]对您来说仍然太长,那么您可以将proc保存为示例变量,并调用相关值,如@p.(:name)

class Foo
  attr_reader :p
  def initialize p
    @p = ->x{p[x]}
  end
  def foo
    do_something_with(@p.(:name))
    ...
  end
end


或者,另一种方法是定义一个调用哈希并应用键的方法。

class Foo
  def initalize p
    @p = p
  end
  def get key
    @p[key]
  end
  def foo
    do_something_with(get(:name))
    ...
  end
end


如果要设置值,您可以定义一个setter方法,并进一步检查是否有无效的键。

class Foo
  Keys = [:name, :age, :email, :gender, :height]
  def initalize p
    raise "Invalid key in argument" unless (p.keys - Keys).empty?
    @p = p
  end
  def set key, value
    raise "Invalid key" unless Keys.key?(key)
    @p[key] = value
  end
  def get key
    @p[key]
  end
  def foo
    do_something_with(get(:name))
    ...
  end
end

fv2wmkja

fv2wmkja8#

本着@steenslag提案的精神,但也从模块中扩展了一些方法:

module Greeting
  def greet
    puts "Hello, my name is #{name} and I'm #{age} years old."
  end
end

Person = Struct.new(:name, :age) do
  include Greeting
end

person = Person.new("Alice", 25)
person.greet # => Hello, my name is Alice and I'm 25 years old.

字符串

相关问题