2016-06-01 2 views
0

Я читаю книгу POODR и использует старый синтаксис для инициализации со значениями по умолчанию. Я хочу реализовать то же самое с новым синтаксисом.ruby ​​initialization with keyword args

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 

Как бы это выглядело с новым ключевым словом 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

'wheel: nil' будет эквивалентно – Stefan

ответ

0

Ваш пример с ключевыми словами аргумент не эквивалентен старому, потому что :wheel потребуется, в то время как в старом коде не было.

Вы не можете использовать аргументы ключевых слов, если вы хотите, чтобы ключевые слова были необязательными.

+0

Agis, и если я сделаю то, что предложил Штефан в комментарии выше? –

1

буквальные эквивалент будет следующим образом:

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), что явно опечатка, но вместо получения ошибки он будет без проблем получать неверные данные (значение cog10).

class Gear 
    def initialize(chainring: 40, cog: 10, wheel: nil) 
    @chainring = chainring 
    @cog = cog 
    @wheel = wheel 
    end 
end 

Это эквивалентно предназначен поведение исходного кода, я думаю. Он ведет себя по-другому, поскольку он не позволяет передавать произвольные ключи, но я не думаю, что это имеет смысл в любом случае. Таким образом, хотя это не эквивалентно, возможно, лучше.

Тем не менее, есть проблема (которая также существует в исходном коде): можно не пройти wheel, делая wheel end up nil. Однако wheel используется безоговорочно (например, в diameter), что означает, что он будет взорваться во время выполнения, когда wheel - nil. Так, что лучше требовать wheel быть переданы:

class Gear 
    def initialize(chainring: 40, cog: 10, wheel:) 
    @chainring = chainring 
    @cog = cog 
    @wheel = wheel 
    end 
end 

Который, конечно, именно то, что нужно было. Это не эквивалент в поведении, но я бы это сделал is эквивалент в умысла и, возможно, намного лучше и правильнее.

+0

Jorg, спасибо за подробный ответ! У меня есть 2 вопроса: 1. Не могли бы вы рассказать мне, что вы используете '@chainring = args [: chainring]' вместо '@chainring = chainring' (вопрос также относится к @cog и @wheel) в последнем примере ? 2. Поэтому, если я хочу сделать колесо опционным, то я могу просто использовать 'wheel: nil' в args, но если я хочу сделать это, то просто используйте' wheel: 'в аргументе? –