Ruby哈希初始化混乱
Ruby Hash initialize confusion
我有两个类.
class Sky
attr_accessor :args
def initialize(args)
@args = args
puts 'Initializing sky'
end
end
class ShadowMask
attr_accessor :sky
def initialize(args)
args.each{|k, v| p "#{k}: #{v.to_s}"}
@sky = args.fetch(:sky, Sky.new({}))
end
end
ShadowMask
可以使用默认 Sky
:
创建
sm_default = ShadowMask.new({})
# Initializing sky
# => #<ShadowMask:0x007fa215230eb0 @sky=#<Sky:0x007fa215230e60 @args={}>>
sm_default.sky
# => #<Sky:0x007fa215230e60 @args={}>
sm_default.sky.args
# => {}
或使用之前创建的 Sky
:
skyobj = Sky.new("Sky Object")
# Initializing sky
# => #<Sky:0x007fa21481a020 @args="Sky Object">
sm = ShadowMask.new(:sky => skyobj)
# "sky: #<Sky:0x007fa21481a020>"
# Initializing sky
# => #<ShadowMask:0x007fa21521ae80 @sky=#<Sky:0x007fa21481a020 @args="Sky Object">>
在第二种情况下,Sky
的实例已经存在,我不想看到 Sky
初始化的输出 Initializing sky
。
我的实际代码的问题是
puts 'Initializing sky'
是对一个方法的调用,该方法执行若干次计算以完成初始化并设置若干个属性。每次创建 ShadowMask
时都无需重复此操作。
有趣的是,如果我替换
@sky = args.fetch(:sky, Sky.new({}))
类似
@sky = args.fetch(:sky, 'AnyString')
它工作正常,但如果需要,我会放弃创建新 Sky
的可能性。
我不确定问题出在语法上还是我犯了概念性错误。
我认为您需要将块传递给 fetch
才能看不到 Initializing sky
:
@sky = args.fetch(:sky) {Sky.new({})}
这背后的想法是,当您调用任何方法时,最初将调用其参数(在本例中 Sky.new({})
)。当您传递块时 - 它将在内部方法 fetch
之后调用,而不是之前。
如果您只想在省略键 :sky
时提供默认 Sky
对象,那么 fetch
是次优选择。这样效果会更好:
@sky = args[:sky] || Sky.new({})
"problem" 和 fetch
是这将导致 nil sm.sky
:
sm = ShadowMask.new(sky: nil)
如果这是您想要的行为,请使用 fetch
。如果不是,请使用 ||
.
我有两个类.
class Sky
attr_accessor :args
def initialize(args)
@args = args
puts 'Initializing sky'
end
end
class ShadowMask
attr_accessor :sky
def initialize(args)
args.each{|k, v| p "#{k}: #{v.to_s}"}
@sky = args.fetch(:sky, Sky.new({}))
end
end
ShadowMask
可以使用默认 Sky
:
sm_default = ShadowMask.new({})
# Initializing sky
# => #<ShadowMask:0x007fa215230eb0 @sky=#<Sky:0x007fa215230e60 @args={}>>
sm_default.sky
# => #<Sky:0x007fa215230e60 @args={}>
sm_default.sky.args
# => {}
或使用之前创建的 Sky
:
skyobj = Sky.new("Sky Object")
# Initializing sky
# => #<Sky:0x007fa21481a020 @args="Sky Object">
sm = ShadowMask.new(:sky => skyobj)
# "sky: #<Sky:0x007fa21481a020>"
# Initializing sky
# => #<ShadowMask:0x007fa21521ae80 @sky=#<Sky:0x007fa21481a020 @args="Sky Object">>
在第二种情况下,Sky
的实例已经存在,我不想看到 Sky
初始化的输出 Initializing sky
。
我的实际代码的问题是
puts 'Initializing sky'
是对一个方法的调用,该方法执行若干次计算以完成初始化并设置若干个属性。每次创建 ShadowMask
时都无需重复此操作。
有趣的是,如果我替换
@sky = args.fetch(:sky, Sky.new({}))
类似
@sky = args.fetch(:sky, 'AnyString')
它工作正常,但如果需要,我会放弃创建新 Sky
的可能性。
我不确定问题出在语法上还是我犯了概念性错误。
我认为您需要将块传递给 fetch
才能看不到 Initializing sky
:
@sky = args.fetch(:sky) {Sky.new({})}
这背后的想法是,当您调用任何方法时,最初将调用其参数(在本例中 Sky.new({})
)。当您传递块时 - 它将在内部方法 fetch
之后调用,而不是之前。
如果您只想在省略键 :sky
时提供默认 Sky
对象,那么 fetch
是次优选择。这样效果会更好:
@sky = args[:sky] || Sky.new({})
"problem" 和 fetch
是这将导致 nil sm.sky
:
sm = ShadowMask.new(sky: nil)
如果这是您想要的行为,请使用 fetch
。如果不是,请使用 ||
.