Непосредственно передать структуру в метод с соответствующими аргументами ключевых слов - PullRequest
1 голос
/ 25 марта 2020

Как видно из заголовка, я пытаюсь передать структуру в метод с аргументами ключевых слов. Поскольку ruby, как правило, довольно кратко, я надеялся, что есть менее подробный метод реализации того, что у меня есть.

Вот класс, с которым я работаю

class WheelStore
  attr_reader :wheels

  def initialize(data: [])
    @wheels = wheelify data
  end

  def diameters
    wheels.map { |wheel| diameter rim: wheel.rim, tire: wheel.tire }
  end

  private

  def diameter(rim:, tire:)
    rim + (tire * 2)
  end

  Wheel = Struct.new :rim, :tire, keyword_init: true
  def wheelify(data)
    data.map { |item| Wheel.new rim: item[0], tire: item[1] }
  end
end

puts WheelStore.new(data: [[10, 2], [3, 2]]).diameters

Вопрос касается метода diameter, который предполагает rim и tire. Я бы хотел, чтобы вызывающая сторона могла просто передать wheel, который представляет собой структуру Wheel, которая реализует rim & tire, в метод diameter.

# verbose
def diameters
  wheels.map { |wheel| diameter rim: wheel.rim, tire: wheel.tire }
end
#better
def diameters
  wheels.map { |wheel| diameter wheel }
end
#best
def diameters
  wheels.map { diameter }
end

Мне любопытно, это просто языковая конструкция, почему мы не можем реализовать последние 2 версии этого diameters метода?

Для справки я много Javascript развитие и то, что я пытаюсь здесь, очень похоже на Javascript Разрушающее задание

1 Ответ

3 голосов
/ 25 марта 2020

Проблема в том, что WheelStore выполняет процедурную работу для Wheel. Вам нужен правильный класс Колеса.

class Wheel
  attr_reader :rim, :tire

  def initialize(rim:, tire:)
    @rim = rim
    @tire = tire
  end

  def diameter
    rim + (tire * 2)
  end
end

Тогда wheelify уходит. Вместо этого используйте Wheel.new напрямую. Инициализируйте только с соответствующими объектами колеса. Это более гибко и эффективно. Вместо того, чтобы сначала преобразовывать данные из исходного формата в формат Array of Arrays, а затем снова в пары ключ / значение, их нужно преобразовать только один раз в пары ключ / значение.

class WheelStore
  attr_reader :wheels

  def initialize(wheels: [])
    @wheels = wheels
  end

  def diameters
    wheels.map { |wheel| wheel.diameter }
  end
end

datum = [["rim1", "tire1"], ["rim2", "tire2"]]
wheel_store1 = WheelStore.new(
  wheels: datum.map { |data| Wheel.new(rim: data[0], tire: data[1]) }
)

datum = [
  { rim: "rim1", tire: "tire1" },
  { rim: "rim2", tire: "tire2" }
]
wheel_store2 = WheelStore.new(
  wheels: datum.map { |data| Wheel.new(**data) }
)

Если у вас есть укажите c форматы данных, которые вы обычно превращаете в Wheels, тогда вы должны создать классовый метод для работы с ними.

class Wheel
  class << self
    def new_from_array(wheel_data)
      new(rim: wheel_data[0], tire: wheel_data[1])
    end
  end
end

datum = [["rim1", "tire1"], ["rim2", "tire2"]]
ws = WheelStore.new(
  wheels: datum.map { |data| Wheel.new_from_array(data) }
)

Если импорт Wheels становится достаточно сложным, вы можете написать WheelImporter.


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

2.6.5 :001 > Wheel = Struct.new :rim, :tire, keyword_init: true
 => Wheel(keyword_init: true) 
2.6.5 :002 > Wheel.class
 => Class 

#best
def diameters
  wheels.map { diameter }
end

2.7 добавлено Нумерованные параметры .

wheels.map { _1.diameter }

До версии 2.7 вы должны объявить аргументы.

Вы можете обойти это с помощью instance_eval и создать свои собственные неявные версии методов Enumerable. Это превращает каждый элемент в тему блока, self.

module Enumerable
  def implied_map(&block)
    map { |a| a.instance_eval(&block) }
  end
end

[1,2,3].implied_map { to_s }       # ["1", "2", "3"]
[1,2,3].implied_map { self.to_s }  # same

... но не делайте этого. instance_eval полезно для записи DSL . Но создание собственных версий стандартных методов означает, что вы создаете свой собственный небольшой отросток Ruby, который другие люди должны будут изучить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...