gpt4 book ai didi

polymorphism - Perl 6 和 `multi method new`

转载 作者:行者123 更新时间:2023-12-02 21:50:46 26 4
gpt4 key购买 nike

我有一个封装 Int 的类 Price。我还希望它有 NumStr 的构造函数。我认为我可以通过使 Price::new 成为具有各种类型约束的多方法来实现此目的,但这不是我期望的行为。看起来 Price.new 完全跳过了构造函数,直接进入 BUILD,绕过了转换逻辑。

通过查看其他 Perl 6 代码,我知道使用 multi method new 是可以接受的。但是,我还没有找到具有不同类型约束的多态构造函数的示例。如何重写此代码以强制其使用构造函数中的转换逻辑?

lib/Price.pm6

#!/usr/bin/env perl6 -w

use v6;

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 $.price;

multi method new(Int $price) {
say "Int constructor";
return self.bless(:$price);
}

multi method new(Num $price) {
say "Num constructor";
return self.new(Int($price * 100));
}

multi method new(Str $price) {
say "String constructor";
$price .= trans(/<-[0..9.]>/ => '');
unless ($price ~~ m/\.\d**2$/) {
die(X::Price::PriceInvalid(:$price));
}
return self.new(Num($price));
}

submethod BUILD(:$!price) { say "Low-level BUILD constructor" }

method toString() {
return sprintf("%.2f", ($!price/100));
}

t/price.t

#!/usr/bin/env perl6 -w

use v6;
use Test;

use-ok 'Price', 'Module loads';
use Price;

# test constructor with Int
my Int $priceInt = 12345;
my $priceIntObj = Price.new(price => $priceInt);
is $priceIntObj.toString(), '123.45',
'Price from Int serializes correctly';

# test constructor with Num
my $priceNum = Num.new(123.45);
my $priceNumObj = Price.new(price => $priceNum);
is $priceNumObj.toString(), '123.45',
'Price from Num serializes correctly';

# test constructor with Num (w/ extra precision)
my $priceNumExtra = 123.4567890;
my $priceNumExtraObj = Price.new(price => $priceNumExtra);
is $priceNumExtraObj.toString(), '123.45',
'Price from Num with extra precision serializes correctly';

# test constructor with Str
my $priceStr = '$123.4567890';
my $priceStrObj = Price.new(price => $priceStr);
is $priceStrObj.toString(), '123.45',
'Price from Str serializes correctly';

# test constructor with invalid Str that doesn't parse
my $priceStrInvalid = 'monkey';
throws-like { my $priceStrInvalidObj = Price.new(price => $priceStrInvalid) }, X::Price::PriceInvalid,
'Invalid string does not parse';

done-testing;

PERL6LIB=lib/perl6 t/price.t的输出

ok 1 - Module loads
Low-level BUILD constructor
ok 2 - Price from Int serializes correctly
Low-level BUILD constructor
not ok 3 - Price from Num serializes correctly
# Failed test 'Price from Num serializes correctly'
# at t/price.t line 18
# expected: '123.45'
# got: '1.23'
Low-level BUILD constructor
not ok 4 - Price from Num with extra precision serializes correctly
# Failed test 'Price from Num with extra precision serializes correctly'
# at t/price.t line 24
# expected: '123.45'
# got: '1.23'
Low-level BUILD constructor
Cannot convert string to number: base-10 number must begin with valid digits or '.' in '⏏\$123.4567890' (indicated by ⏏)
in method toString at lib/Price.pm6 (Price) line 39
in block <unit> at t/price.t line 30

最佳答案

您编写的所有new 多重方法都采用一个位置参数。

:( Int $ )
:( Num $ )
:( Str $ )

尽管您正在使用命名参数调用 new

:( :price($) )

问题是,由于您没有编写接受这一点的代码,因此它使用 Mu 提供的默认 new

<小时/>

如果您不想允许内置的 new,您可以编写一个 proto 方法来阻止它向上搜索继承链。

proto method new (|) {*}

如果您愿意,您还可以使用它来确保所有潜在的子类也遵循只有一个位置参数的规则。

proto method new ($) {*}
<小时/>

如果您想使用命名参数,请使用它们。

multi method new (Int :$price!){…}
<小时/>

您可能想单独保留 new 并使用多子方法 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 相同/11e0
我还将输出除以 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));
}

关于polymorphism - Perl 6 和 `multi method new`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50788338/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com