Упростите вызов общего метода - PullRequest
0 голосов
/ 31 января 2019

У меня есть такой класс:

class Foo {
    method some-method(Str $name) { ... }
}

Простое использование:

my $foo = Foo.new;

$foo.some-method("peter");

Поскольку "some-method" будет вызываться довольно часто, я хотел бы сделатьчто-то, чтобы позволить пользователям использовать его, как показано ниже:

$foo.peter;

Я знаю, что FALLBACK сделает эту работу, но он был использован для другого метода.Я попытался определить инфиксный оператор:

sub infix:<%>(Foo $foo, $name) {
    $foo.some-method($name);
}

Код ниже работает, но двойная кавычка раздражает.

$foo % "peter";

Так есть ли способ избежать кавычки?Или любой способ упростить вызов?

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Существует способ, которым вы можете использовать FALLBACK для более чем одной операции, при условии, что они в некотором роде различаются.

  • Проверяя некоторые свойства объекта:

    class Foo {
      # this could be set as part of `new`/`BUILD`
      has %!special = ( "peter" => 42 );
    
      multi method FALLBACK ( $name where (%!special{$name}:exists) ) {
        %!special{$name}
      }
    
      multi method FALLBACK ( $other ) {
        $other.tc
      }
    }
    
    with Foo.new {
      say .paul; # Paul
      say .peter; # 42
    }
    

    У этого есть потенциальная проблема действия на расстоянии.

  • С другим числом или типами аргументов:

    class Bar {
      multi method FALLBACK ( Str:D $name ) {
        $name.tc
      }
      multi method FALLBACK ( Str:D $name, Real:D $number ) {
        $name.tc, 1 / $number
      }
      multi method FALLBACK ( Str:D $name, Str:D $other ) {
        $name.tc, $other.uc
      }
    }
    
    with Bar.new {
      say .paul;          # Paul
      say .peter(42);     # Peter, 0.02381
      say .peter('Paul'); # Peter, PAUL
    }
    

Вы можете использовать .[…] для аргумента Int.

class Baz {
  method AT-POS ( $arg ) { say "Baz[$arg]" }
}
Baz.new[42,32]; # Baz[42]
                # Baz[32]

Встроенный postcircumfix:« [ ] » приводит аргументы к Int, но вы можете добавить новый вмикс.
(При этом есть несколько предостережений.)

multi sub postcircumfix:<[ ]> ( Baz:D $b, $a ) is export {
  # $b.AT-POS( $a )

  $b.some-method( $a )
}

Вы можете использовать .<…> для Strs, разделенных пробелами, или .{…} для произвольных значений.

class Other {
  multi method AT-KEY ( Str:D $name ){
    $name.tc
  }
  multi method AT-KEY ( Real:D $number ){
    1 / $number
  }
}

with Other.new {
  say $_<peter>;     # Peter
  say $_.<paul>;     # Paul
  say .<peter paul>; # Peter Paul
  # note that AT-Key got called twice

  say $_{42,'peter'}; # 0.02381, Peter
  # note that AT-Key got called twice
}

Вы можете сделать так, чтобы ваш объект вызывался.

class Fubar {
  multi method CALL-ME ( Str:D $name ){
    $name.tc
  }
  multi method CALL-ME ( Real:D $number ){
    1 / $number
  }
  multi method CALL-ME ( +@args ){
    @args.map: {self.CALL-ME($_)}
  }
}

with Fubar.new {
  say $_('peter');   # Peter
  say $_(42);        # 0.02381

  # this calls the +@args one
  say $_('paul',32); # Paul, 0.03125
}

Вы должны действительно подумать о своем API, прежде чем делать что-либо из этого.

0 голосов
/ 31 января 2019

Как уже указывал Курт Тильмес, вы можете заставить свой Foo объект действовать как Associative (или Hash):

class Foo {
    method some-method(Str $name) { ... }
    method AT-KEY(Str $name) { self.some-method($name) }
}
my $foo = Foo.new;
say $foo<peter>;   # same as $foo.some-method("peter")

Конечно, метод AT-KEY может бытьмульти, так что вы можете сыграть все виды трюков с этим.

class Foo {
    method some-method(Str $name) { "$name is ok" }
    multi method AT-KEY("peter")   { "peter is special" }
    multi method AT-KEY(Str $name) { self.some-method($name) }
}
my $foo = Foo.new;
say $foo<peter>;   # "peter is special"
say $foo<joe>;     # "joe is ok"
...