Уточнение типа в кристалле из доходных блоков - PullRequest
0 голосов
/ 23 октября 2019

Я использовал Enumerable # select (& block) , чтобы попытаться уточнить массив для элементов определенного типа с arr.select { |el| el.is_a?(Bar) }, но это не сработало.

Затем я увиделметод Enumerable # select (type) , и это сработало: https://play.crystal -lang.org / # / r / 7v05

Но я заметил, что дваопределения очень похожи в моем случае.

Enumerable # select (& block) :

  def select(&block : T ->)
    ary = [] of T
    each { |e| ary << e if yield e }
    ary
  end

Enumerable # select (type)

  def select(type : U.class) forall U
    ary = [] of U
    each { |e| ary << e if e.is_a?(U) }
    ary
  end

Есть ли способ сообщить компилятору, что блок select уточняет тип элементов (возможно, путем добавления типа в блок каким-либо образом)? Или есть причина, по которой компилятор не может знать, что утверждает блок?

1 Ответ

2 голосов
/ 23 октября 2019

Проблема здесь в том, что массив должен быть создан с правильным типом. Таким образом, основное различие двух методов:

ary = [] of T

, где T - аргумент типа Enumerable, который вы вызываете select, по сравнению с

ary = [] of U

, где U является аргументом типа, специфичным для этого метода (forall U).

Итак, чтобы сделать то, что вы хотите, нам нужно знать, что блок фильтрует элементы, но это никак не кодируется в блоках. тип. Он имеет только список типов аргументов и возвращаемый тип. Тем не менее, мы можем объединить два метода в нечто вроде:

module Enumerable(T)
  def select(type : U.class) forall U
    ary = [] of U
    each { |e| ary << e if yield e if e.is_a? U }
    ary
  end
end
...