Все написанные вами new
multi-методы принимают один позиционный аргумент.
:( Int $ )
:( Num $ )
:( Str $ )
Вы вызываете new с именованным аргументом, хотя
:( :price($) )
Проблема в том, чтотак как вы не написали тот, который принял бы это, он использует значение по умолчанию new
, которое обеспечивает Mu
.
Если вы не хотите разрешать встроенный new
,вы можете написать метод proto
, чтобы он не мог искать в цепочке наследования.
proto method new (|) {*}
Если вы хотите, вы также можете использовать его, чтобы гарантировать, что все потенциальные подклассы также следуют правилу о наличии точноодин позиционный параметр.
proto method new ($) {*}
Если вы хотите использовать именованные параметры, используйте их.
multi method new (Int :$price!){…}
Возможно, вы захотите оставить new
в покое и использоватьmulti submethod BUILD
вместо.
multi submethod BUILD (Int :$!price!) {
say "Int constructor";
}
multi submethod BUILD (Num :$price!) {
say "Num constructor";
$!price = Int($price * 100);
}
multi submethod BUILD (Str :$price!) {
say "String constructor";
$price .= trans(/<-[0..9.]>/ => '');
unless ($price ~~ m/\.\d**2$/) {
die(X::Price::PriceInvalid(:$price));
}
$!price = Int($price * 100);
}
На самом деле я всегда умножил бы ввод на 100
, так что 1
будет таким же, как "1"
и 1/1
и 1e0
.
Я бы также разделил вывод на 100, чтобы получить Крысу.
unit class Price:ver<0.0.1>;
class X::Price::PriceInvalid is Exception {
has $.price;
method message() {
return "Price $!price not valid"
}
}
# Price is stored in cents USD
has Int $.price is required;
method price () {
$!price / 100; # return a Rat
}
# Real is all Numeric values except Complex
multi submethod BUILD ( Real :$price ){
$!price = Int($price * 100);
}
multi submethod BUILD ( Str :$price ){
$price .= trans(/<-[0..9.]>/ => '');
unless ($price ~~ m/\.\d**2$/) {
X::Price::PriceInvalid(:$price).throw;
}
$!price = Int($price * 100);
}
method Str() {
return sprintf("%.2f", ($!price/100));
}