Массив объектов - PullRequest
       27

Массив объектов

6 голосов
/ 23 мая 2019

Допустим, я хочу подключиться к двум репозиториям пакетов, сделать запрос для имени пакета, объединить результат из репозиториев и обработать его (фильтр, уникальность, расставить приоритеты, ...), что является хорошим способом сделать что?

Что я думаю о создании Array из двух Cro::HTTP::Client объектов (с base-uri для каждого репо), и когда мне нужно сделать HTTP-запрос, я вызываю @a>>.get, затем обрабатываю результат из репо вместе.

Я приложил фрагмент того, что я пытаюсь сделать. Но я хотел бы посмотреть, есть ли лучший способ сделать это. или если упоминание о подходе в следующей ссылке подходит для этого варианта использования! https://perl6advent.wordpress.com/2013/12/08/day-08-array-based-objects/

use Cro::HTTP::Client;

class Repo {

  has $.name;
  has Cro::HTTP::Client $!client;
  has Cro::Uri $.uri;
  has Bool $.disable = False;

  submethod TWEAK () {
    $!client = Cro::HTTP::Client.new(base-uri => $!uri, :json);
  }

  method get (:$package) {

    my $path = <x86_64?>;
    my $resp = await $!client.get($path ~ $package);
    my $json = await $resp.body;
    return $json;
  }
}


class AllRepos {

  has Repo @.repo;

  method get (:$package) {

    # check if some repos are disabled
    my @candidate = @!repo>>.get(:$package).unique(:with(&[eqv])).flat;

    # do furthre processign of the data then return it;
    return @candidate;

  }
}

my $repo1 = Repo.new: name => 'repo1', uri => Cro::Uri.new(:uri<http://localhost:80>);
my $repo2 = Repo.new: name => 'repo2', uri => Cro::Uri.new(:uri<http://localhost:77>);

my @repo = $repo1, $repo2;

my $repos = AllRepos.new: :@repo;


#my @packages = $repos.get: package => 'rakudo';

1 Ответ

6 голосов
/ 23 мая 2019

Допустим, я хочу подключиться к двум репозиториям пакетов, сделать запрос на имя пакета, объединить результат из репозиториев и обработать его (фильтр, уникальный, расставить приоритеты, ...), что является хорошим способом сделать что?

Код, который вы показали, выглядит как один хороший способ в принципе , но на практике это не так.

Гипероператоры , такие как >>:

  • Распределить операцию (в вашем случае подключиться и сделать запрос) ...

  • ... до листьев одной или двух входных составных структур данных (в вашем случае элементы одного массива @!repo) ...

  • ... с логически параллельной семантикой (используя гипероператор, вы заявляете, что берете на себя ответственность за то, чтобы думать, что параллельные вызовы операции не будут мешать друг другу, что звучит разумно для подключения и запроса) ...

  • ... и затем возвращает результирующую составную структуру данных с той же формой, что и исходная структура, если гипероператор является унарным оператором (что применимо в вашем случае, потому что вы применили >>, который является унарным оператор, который принимает один аргумент слева, поэтому результат >>.get - это просто новый массив, такой же как ввод @!repo), или чья форма является гипер-комбинацией форм пары структур, если гипероператор - это бинарный оператор, такой как >>op<< ...

  • ... который затем может быть обработан (в вашем случае, с .unique, который даст результирующее Seq) ...

  • ... элементы которого вы затем назначаете обратно в другой массив (@candidate).

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

Вместо этого я предлагаю вам рассмотреть:

  • Использование map для распределения операции по нескольким элементам (поверхностным образом; map не рекурсивно спускается в глубокую структуру, такую ​​как гипероператоры, deepmap и т. Д. , но это нормально для вашего варианта использования) ...

  • ... в сочетании с race методом , который распараллеливает метод, который он использует.

Так что вы можете написать:

my @candidate =
  @!repo.hyper.map(*.get: :$package).unique(:with(&[eqv])).flat;

В качестве альтернативы, проверьте задание 94 в Использование Perl 6 .

, если упоминание подхода в следующей ссылке подходит для этого варианта использования! https://perl6advent.wordpress.com/2013/12/08/day-08-array-based-objects/

Я так не думаю. Речь идет о создании контейнера общего назначения, который похож на массив, но с некоторыми отличиями от встроенного Array, который стоит запечь в новый тип.

Я могу только представить себе такие вещи, которые неопределенно связаны с вашим вариантом использования - например, тип массива, который автоматически гиперраспределяет вызовы методов, вызванные на нем, если они определены на Any или Mu (вместо Array или List), т.е. выполняет то, что я описал выше, но с кодом @!repo.get... вместо hyper @!repo.map: *.get .... Но стоило ли это того (предполагая, что это сработает - я не думал об этом, кроме того, что придумал идею для этого ответа)? Я сомневаюсь в этом.

В целом ...

Кажется, что то, что вы ищете, - это материал, похожий на кулинарную книгу. Возможно, вопрос размещен на в порядке reddit sub / r / perl6 ?

...