我正在阅读POODR书,它使用旧语法进行初始化,使用默认值。我想用新语法实现相同的功能。
class Gear
attr_reader :chainring, :cog, :wheel
def initialize(args)
@chainring = args.fetch(:chainring, 40)
@cog = args.fetch(:cog, 10)
@wheel = args[:wheel]
end
def gear_inches
ratio * diameter
end
def diameter
wheel * diameter
end
end
Gear.new(chainring: 52, cog: 11, wheel: Wheel.new(26,1.5)).gear_inches
使用new关键字args会如何?这是我在下面的猜测,但不确定它是否与上面的车轮相同。
class Gear
attr_reader :chainring, :cog, :wheel
def initialize(chainring: 40, cog: 10, wheel:) #is this good here for wheel?
@chainring = chainring
@cog = cog
@wheel = wheel #is this good here for wheel?
end
......
end
答案 0 :(得分:2)
literal 等价物将是:
class Gear
def initialize(**args)
@chainring = args.fetch(:chainring, 40)
@cog = args.fetch(:cog, 10)
@wheel = args[:wheel]
end
end
原始代码允许传递任意键,只是忽略它不需要的键,因此,我们使用** ksplat来允许任意参数。
我们可以将代码重构为:
class Gear
def initialize(chainring: 40, cog: 10, **args)
@chainring = chainring
@cog = cog
@wheel = args[:wheel]
end
end
这读得稍微好一点。但它仍然是糟糕的设计:为什么允许用户传递任意键?当未使用的密钥通过时,它很可能是一个错误。例如。用户调用Gear.new(cgo: 20)
,这显然是一个错字,但他没有收到错误,而是默默地收到错误的数据(cog
10
}。
class Gear
def initialize(chainring: 40, cog: 10, wheel: nil)
@chainring = chainring
@cog = cog
@wheel = wheel
end
end
这相当于原始代码的预期行为,我猜。它的行为有所不同,因为它不允许传递任意键,但我认为这无论如何都没有意义。所以,虽然不等同,但可以说是更好。
但是,仍有问题(原始代码中也存在):可能无法通过wheel
,使wheel
结束nil
。但是,无条件地使用wheel
(例如diameter
),这意味着,wheel
为nil
时,它会在运行时爆炸。因此,最好要求wheel
传递:
class Gear
def initialize(chainring: 40, cog: 10, wheel:)
@chainring = chainring
@cog = cog
@wheel = wheel
end
end
当然,这正是你所拥有的。这 not 在行为上是等效的,但我认为 等同于 intent ,可以说它更好更正确。
答案 1 :(得分:0)
您的带有关键字参数的示例与旧方法不同,因为将需要:wheel
,而在旧代码中则不是。
如果您希望关键字是可选的,则无法使用关键字参数。