编写严格编译代码的最佳方法

发布于 2024-09-11 06:35:19 字数 1394 浏览 3 评论 0原文

检查提供给子例程的参数以进行严格编译的最佳方法是什么(我的解决方案有效,但有更好的方法?)

我有一个大型旧库,我想更正代码,以便我可以添加 use strict;对此,我的大多数错误都是这样的(在页面加载时会生成 189 个错误):

Use of uninitialized value in string eq at ../lib/cgilibtest.pl line 1510
Use of uninitialized value in concatenation (.) or string at ../lib/cgilibtest.pl line 1511.

它们是由这样编写的子例程生成的:

#!/usr/bin/perl -w
sub example()
{
    my $var1 = shift @_;
    my $var2 = shift @_;
    my $var3 = shift @_;
    if($var2 eq ""){var2 = "something";} # this line generates the first type of error beacause $var2 is not defined
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; # this line generates the second type of error, beacause $var3 is not defined
}
print "Content-type: text/html\n\n";
$someVar = &example("firstVar");
print $someVar;

我的解决方案是使用三元运算符并将它们写为:

#!/usr/bin/perl -w
use strict;

sub example()
{
    my $var1 = ($_[0])?$_[0]:"";
    my $var2 = ($_[1])?$_[1]:"something";
    my $var3 = ($_[2])?$_[2]:"";
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
print "Content-type: text/html\n\n";
my $someVar = &example("firstVar");
print $someVar;

在 PHP 中我使用 函数示例 ($var1, $var2 = null, $var3 = null){...}

PS 如果有人知道关于“在 Perl 中编写严格代码”的好教程或手册,请留下一个链接。

谢谢。

What is the best way to check arguments provided to subroutines to compile with strict ( my solution works but there is a better way of doing it ? )

I have a large old library, I want to correct the code so I can add use strict; to it, most of my error are like this (on a page load it generates 189 errors):

Use of uninitialized value in string eq at ../lib/cgilibtest.pl line 1510
Use of uninitialized value in concatenation (.) or string at ../lib/cgilibtest.pl line 1511.

They are generated by subroutines writen like this:

#!/usr/bin/perl -w
sub example()
{
    my $var1 = shift @_;
    my $var2 = shift @_;
    my $var3 = shift @_;
    if($var2 eq ""){var2 = "something";} # this line generates the first type of error beacause $var2 is not defined
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; # this line generates the second type of error, beacause $var3 is not defined
}
print "Content-type: text/html\n\n";
$someVar = &example("firstVar");
print $someVar;

My solution was to use the ternary operator and write them as:

#!/usr/bin/perl -w
use strict;

sub example()
{
    my $var1 = ($_[0])?$_[0]:"";
    my $var2 = ($_[1])?$_[1]:"something";
    my $var3 = ($_[2])?$_[2]:"";
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
print "Content-type: text/html\n\n";
my $someVar = &example("firstVar");
print $someVar;

in PHP I use function example ($var1, $var2 = null, $var3 = null){...}

P.S. If someone knows a good tutorial or manual about "write strict code in perl" please leave a link to it.

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼眸里的快感 2024-09-18 06:35:19
  • 我认为 PBP (Perl 最佳实践)是一本关于“严格”风格的好读物。如果
    如果你按照它所说的去做,你将至少编写符合严格警告的代码。

我看到的是 uninit 警告。而且,uninit 警告带有 警告,而不是严格。尽管它通常与严格齐头并进。

对于您的特定错误,重要的是要认识到,当您移动 arg 数组(我倾向于将其称为“甲板”)时,方法/函数的用户可能没有在该位置传递任何内容。因此,这是一个很好的习语;

my $var1 = shift || '';

'' 尚未初始化,因此不会收到警告。三元数也是一种很好的方法,我在生产代码中充分使用了它们。

当然,还有另一个问题。如果你看一下上面的代码,我在期待什么?我预计 $var1 可能尚未传递任何数据。如果是这种情况,并且我仍然想将其字符串化 - 并且本地代码中有足够这样的情况 - 有时你只需这样做:

# don't bug me about uninitialized stringed values
# just concatenate them
no warnings 'uninitialized'; 
return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; 

它相当于用一堆代码来执行此操作变量:

my $var = shift || '';

这个想法并不是对未初始化的数据感到惊讶——拥有适合实例的策略,而不是盲目地按照标准进行编码。

由于您的子程序足够简单,因此上面的代码将起作用。但您可能希望让它在未来做更多的事情,所以我建议使用以下构造来隔离我们可以接受未初始化值的部分以及您不想被抓住的部分。

{   no warnings 'uninitialized';
    $string = ...;
}
$obj_that_should_be_defined->do_something_objecty( $string );

do 块对此也很有用。

$obj_that_should_be_defined->do_something_objecty( 
    do { no warnings 'uninitialized'; sprintf( ... ); }
);

当然,作为变量传递的任何内容,您也可以使用 map 进行过滤。如果您只想处理 undef,则以下方法有效。

$object->method( map { defined() ? $_ : '' } @anon_args );  
  • 我要警告的是,任何尚未在范围内检查过的内容(来自其他地方的任何内容:参数、IO、正则表达式捕获、函数返回)都可能未初始化。良好的编码实践应该让您检查所有这些事情如果您在这种情况下关心它们是否undef

现在,很多时候人们检查未定义的变量只是为了发牢骚。由于 Perl 的消息已经变得更好,也许它们将来可以改进。可能没有必要专门发出嘎嘎声。

my $feldman = Feldman->new( qw<here is some data for you> )
    or die 'Could not create Feldman!'
    ;
$feldman->dont_just_sit_there_do_something();

然而,如果没有显式的or die,如果$feldman未定义,上面的代码肯定会死掉。您无法对未定义的值调用方法,因此存在不专门检查的情况。如果 $feldman 未定义,那么您没有创建它,您只需从未定义到错误消息进行多一层推断。两者都没有告诉我们为什么该对象没有被创建,只是它没有被创建。 (构造函数至少应该对它没有的东西吹毛求疵。)

  • I think the PBP (Perl Best Practices) is a good read on a "strict" style. If
    you follow what it says, you will at least be writing code compliant with strict and warnings.

What I see is uninit warnings. And, uninit warnings come with warnings, not strict. Though it usually goes hand in hand with strict.

For your particular error, it's important to realize that when you shift the arg array (which I have a tendency to call "deck") that the user of the method/function might not have passed anything in that position. Thus this is a good idiom;

my $var1 = shift || '';

'' is not uninitialized, and so won't get the warning. Ternaries are also a good means and I use them enough in my production code.

Of course, there's another issue though. If you take a look at the code above, what am I expecting? I'm expecting that $var1 might not have been passed any data. If that is the case, and I still want to stringify it--and there are enough cases like this in the local code--sometimes you just do this:

# don't bug me about uninitialized stringed values
# just concatenate them
no warnings 'uninitialized'; 
return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; 

It's equivalent code to doing this with a bunch of variables:

my $var = shift || '';

The idea is not to be taken by surprise with uninitialized data--having a policy that fits the instance, rather than slavishly coding to a standard.

Since your sub is easy enough, the above code will work. But you probably want to make it do more in the future, so I suggest the following construct to isolate the parts that we're okay with uninitialized values and where you don't want to be caught unaware.

{   no warnings 'uninitialized';
    $string = ...;
}
$obj_that_should_be_defined->do_something_objecty( $string );

do blocks are also useful for this.

$obj_that_should_be_defined->do_something_objecty( 
    do { no warnings 'uninitialized'; sprintf( ... ); }
);

Of course anything that you pass as a variable, you can also filter with a map. The following works if you just want to take care of undefs.

$object->method( map { defined() ? $_ : '' } @anon_args );  
  • I good word of warning is that anything that hasn't already been checked in the scope--anything coming from somewhere else: parameter, IO, regex capture, returns from functions--can be uninitialized. The practice of good coding should have you checking all these things IF you care in that instance whether they are undef of not.

Now, a lot of times people check for undefined variables just to croak. Since Perl's messages have gotten better, and perhaps if they could improve in the future. It might not be necessary to croak specifically.

my $feldman = Feldman->new( qw<here is some data for you> )
    or die 'Could not create Feldman!'
    ;
$feldman->dont_just_sit_there_do_something();

However without the explicit or die, the code above will definitely die if $feldman is undefined. You can't call a method on an undefined value, so there is case for not specifically checking. If $feldman is undefined, then you didn't create it, there is just one more level of inference you have to make from undefined to the error message. Neither tells us why the object was not created, just that it wasn't. (The constructor should at least have carped about something it didn't have.)

眼趣 2024-09-18 06:35:19
sub example {
  my $var1 = shift || '';
  my $var2 = shift || 'something';
  my $var3 = shift || '';

  return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
sub example {
  my $var1 = shift || '';
  my $var2 = shift || 'something';
  my $var3 = shift || '';

  return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
亽野灬性zι浪 2024-09-18 06:35:19

我赞同查看Perl 最佳实践的建议。达米安康威是一位伟大的老师。还要记住,这本书并不是教条式地阅读,即使你不采纳的建议也值得考虑。

对于全部采用相同默认值的位置参数,我经常这样做:

sub example {
    my ($var1, $var2, $var3) = map { defined() ? $_ : '' } @_;
}

然而,更灵活的是编写使用命名参数的函数。这种方法有几个好处,其中之一是可以轻松处理默认值:

sub example {
    my %DEFAULTS = ( foo => 0, bar => '', fubb => 'blah' );

    # When the hashes are merged, user-supplied arguments
    # will trump the defaults.
    my %args = (%DEFAULTS, @_);
}

example(foo => 123);

如果我没记错的话,PBP 讨论了这种合并哈希的技巧,这在许多情况下都很有用。

I would second the recommendation to look at Perl Best Practices. Damian Conway is a great teacher. Also bear in mind that the book is not intended to be read dogmatically, and even suggestions that you don't adopt are worth thinking over.

For positional arguments that all take the same default value, I often do something like this:

sub example {
    my ($var1, $var2, $var3) = map { defined() ? $_ : '' } @_;
}

Even more flexible, however, is to write functions that use named arguments instead. This approach has several benefits, one of them being the ease with which default values can be handled:

sub example {
    my %DEFAULTS = ( foo => 0, bar => '', fubb => 'blah' );

    # When the hashes are merged, user-supplied arguments
    # will trump the defaults.
    my %args = (%DEFAULTS, @_);
}

example(foo => 123);

If I recall correctly, PBP discusses this trick of merging hashes, which is useful in many contexts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文