我有這個模塊,它有Readonly一個默認值的常量,如果呼叫者未指定值,則使用該常量。
package Mcve;
use strict;
use warnings;
use Readonly;
Readonly our $CONST => 123;
sub new {
my ($class, %args) = @_;
my $self = bless{}, $class;
# uncoverable condition right
# uncoverable condition false
# uncoverable branch false
$self->{'CONST'} = $args{'CONST'} || $CONST;
return $self;
}
還有一個測驗用例:
use strict;
use warnings;
use base 'Test::Class';
use Test::More;
use Mcve;
__PACKAGE__->runtests() unless caller;
sub uses_default_arg: Test {
my $mcve = Mcve->new();
is($mcve->{'CONST'}, 123);
}
sub overrides_default_arg: Test {
my $mcve = Mcve->new('CONST' => 456);
is($mcve->{'CONST'}, 456);
}
當我用 收集測驗覆寫率時Devel::Cover,它并沒有看到它$COVER總是被定義,所以“兩個值都是假的”這個條件永遠不會被覆寫。我嘗試根據
我如何判斷Devel::Cover這種情況是無法發現的?
(這是 Perl 5.34 和 Devel::Cover 1.36 版)
uj5u.com熱心網友回復:
如果你使用一個永遠不會為假的值作為條件,你需要條件嗎?通常,當我發現像這樣難以描述的情況時,我會意識到問題出在我的代碼上,而不是工具上。
你的代碼告訴程式員你想要一個默認值,因為我們已經習慣了(盡管我會問這是一個代碼審查,因為我想知道為什么 0 不能是一個有效值)。但是,代碼實際上是說要在邏輯上組合兩個雙值(真/假)值以得出一個值:
$self->{'CONST'} = $args{'CONST'} || $CONST;
但是,您真正想要的是一組默認值。與其修復物件(尤其是通過直接訪問其資料結構),不如修復傳入的引數,使其在創建物件之前具有默認值。我覺得這更干凈一些,因為該物件沒有考慮兩條路徑:
sub new {
my ($class, %args) = @_;
$args{'CONST'} = $CONST unless $args{'CONST'};
my $self = bless { }, $class;
...
return $self;
}
這也可能顯示為類似這樣,您可以通過讓后面的鍵值對覆寫來自的鍵值對來擺脫條件$defaults:
sub new {
state $defaults = { CONST => $CONST };
my ($class, %args) = @_;
%args = ( %$defaults, %args );
my $self = bless { }, $class;
...
return $self;
}
在此之后,您可能需要一個驗證引數的步驟,您可以在其中捕獲傳遞錯誤值的人。如果您真的不希望有人將0其用作CONST值,我真的想要一個警告(或例外,無論如何)我傳入的顯式值無效。你的原始代碼默默地替換了它,所以我沒有發現我給你的值被忽略了。在移動代碼以停止使用邏輯運算子時,您會再次遇到更好的情況。
這通常對我的代碼來說要好得多,因為我現在有一種簡單的方法來指定和分配默認值。我只是在一個明確標記為默認值的地方添加新的默認值。如果我有另一個默認值,我的代碼結構不會改變。
我更喜歡結構是穩定的(有一個叫做 0,1,Infinity 規則的東西)而不是對外部工具進行奇怪的調整,然后你必須將其作為知識傳遞給未來必須處理代碼的人。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/495703.html
