class Foo
attr_accessor :name, :age, :email, :gender, :height
def initalize params
@name = params[:name]
@age = params[:age]
@email = params[:email]
.
.
.
end
这似乎是一种愚蠢的做法。在 Ruby 中初始化对象的更好/更惯用的方法是什么?
红宝石 1.9.3
class Foo
attr_accessor :name, :age, :email, :gender, :height
def initalize params
@name = params[:name]
@age = params[:age]
@email = params[:email]
.
.
.
end
这似乎是一种愚蠢的做法。在 Ruby 中初始化对象的更好/更惯用的方法是什么?
红宝石 1.9.3
您可以只遍历键并调用设置器。我更喜欢这个,因为如果您传递无效的密钥,它会捕获。
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
def initialize(params)
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
通过一些概括来利用 Joshua Cheek 的回答
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>
注意如果已经使用了初始化混合并且我们需要自定义初始化,我们只需调用 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">
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
为什么不直接明确指定一个实际的参数列表?
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
以不正确的数量调用则引发错误)。
使用 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'
如果您收到一个散列作为唯一参数,为什么不将其保留为实例变量?每当您需要一个值时,请从哈希中调用它。您可以保持实例变量名称简短,以便可以轻松调用它。
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