多态 – Perl 6和`multi method new`

前端之家收集整理的这篇文章主要介绍了多态 – Perl 6和`multi method new`前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个封装Int的类Price.我也希望它有Num和Str的构造函数.我认为我可以通过使Price :: new成为具有各种类型约束的多方法来实现这一点,但这不是我期望的行为.看起来Price.new正在完全跳过构造函数并直接进入BUILD,绕过了构建逻辑.

我知道通过查看其他Perl 6代码,使用multi方法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));
}

吨/ 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(),'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(),'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(),'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

解决方法

您编写的所有新多方法都采用一个位置参数.
:( Int $)
:( Num $)
:( Str $)

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

:( :price($) )

问题是因为你没有写一个会接受它的,它使用Mu提供的默认新.

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

proto method new (|) {*}

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

proto method new ($) {*}

如果要使用命名参数,请使用它们.

multi method new (Int :$price!){…}

您可能希望单独留下新的并使用多子方法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));
}

猜你在找的Perl相关文章