【问题标题】:Topicalising a variable using "for" is apparently bad. Why?使用“for”对变量进行主题化显然很糟糕。为什么?
【发布时间】:2017-10-20 07:58:00
【问题描述】:

所以I answered a question on SO and got a lot of flack for it。 我已经使用 Perl 很多年了,并且经常使用这种主题化。

让我们从一些代码开始。我在这些示例中进行搜索和替换。这个想法是从两个字符串中搜索onethree并替换它们。

$values = 'one two three four five';
$value2 = 'one 2 three four 5';

$values =~ s/one//g;
$values =~ s/three//g;

$values2 =~ s/one//g;
$values2 =~ s/three//g;

这段代码很简单,大家都接受。

我还可以构建一个数组或散列,其中包含要搜索和替换的值列表,这也是可以接受的。

但是,当我构建一个脚本来主题化 $values$values2 并减少构建脚本的输入量时,它似乎被误解了?

这里是代码。

$values = 'one two three four five';
$value2 = 'one 2 three four 5';

for ( $values, $values2 ) {
    s/one//g;
    s/three//g;
}

上面的代码将在for 块期间对变量进行主题化,但许多程序员反对这一点。我想了解为什么这是不可接受的?

【问题讨论】:

  • 好吧。一方面,通过就地改变事物,你有点生活在边缘,但这本身当然不是问题。这样的代码很容易演变成维护者的陷阱;这是一个问题。您展示的示例并没有为您节省太多,并且比其他方式不太清楚。但是,当这正是需要做的事情时,我会毫不犹豫地做s/$patt/$repl/ for @ary。我的 .02
  • 我找到了您的答案并将其链接。两件事:只有一个人不喜欢它,其中的代码与您在这里发布的不同。
  • 我同意主要方面是它让维护人员感到困惑。如果我在$work 的代码库中遇到这段代码,我会重构它。
  • 谢谢@simbabque。你们帮我确认了我的想法:)
  • @zdim: “这样的代码很容易演变成维护者的陷阱” 那么你反对使用$_吗?否则我看不到你的意见?

标签: perl scalar


【解决方案1】:

有几点需要考虑。


您的代码对变量列表执行多次替换。你可以不使用$_

for my $s ($values, $values2) {
    $s =~ s/one//g;
    $s =~ s/three//g;
}

我个人认为上面的代码没什么问题。

$_ 的一般问题是它不是局部变量。例如。如果您的for 循环的主体调用了一个函数(调用函数...),该函数修改了$_ 而没有对其进行本地化(例如,通过分配给它或使用裸s/// 或使用while (<...>)),那么它将覆盖您正在迭代的变量。使用my 变量,您将受到保护,因为其他函数无法看到您的局部变量。

也就是说,如果您的其余代码没有这个错误(在 $_ 上乱写而不进行本地化),$_ 在这里可以正常工作。


但是,人们最初抱怨的答案中的代码不同:

for ($brackets) {
    s/\\left/(/g;
    s/\\right/)/g;
}

在这里,您并没有尝试对许多变量执行相同的替换;您只是通过摆脱 $brackets =~ 部分来节省自己的打字时间:

$brackets =~ s/\\left/(/g;
$brackets =~ s/\\right/)/g;

使用显式循环变量不是解决方案,因为您仍然需要在每一行输入$foo =~

这更多的是品味问题。您仅使用 for 来实现其别名效果,而不是循环多个值。就我个人而言,我仍然可以接受。

【讨论】:

  • 答案中使用for 的方式让我想起了Visual Basic 之类的语言,其中有一个with block(这是.net,我的意思是VB5,但找不到它)。 JavaScript also has that。 Perl 中的 for 循环可以用来做同样的事情,但正如 melpomele 所说,它带有副作用,而其他语言中的实现正是为此而没有的。
  • 谢谢你们!我有我的答案。
  • “我个人认为上面的代码没有任何问题” 和*“我个人对此还是可以的”* 你是说你对OP 版本使用$_ 并认为需要明确提及控制变量或对象变量本身?
  • for ($text) { s/\\left/(/g; s/\\right/)/g; } 的问题是正则表达式引擎的两种用途!我会使用my %brackets = ( left => "(", right => ")" ); $text =~ s/\\(left|right)/$brackets{$1}/g;
  • @GerhardBarnard:看来,在我在你的批评者耳边说了一句话,并向版主提出了话题后,你的负面评论消失了,你收回了你的一个反对票。干得好。
【解决方案2】:

perldoc perlsyn 有这个

foreach 是设置主题化器的非实验性方法。

OP 的构造是编写 Perl 代码的一种完全有效的方式。我对他们早期答案的唯一规定是

  • 与此处的示例不同,只有两个操作应用于单个变量。这只是比简单地写两个替换更简短,我不会在这里打扰,尽管我可能考虑

    s/one//g, s/three//g for $value;
    
  • 除了主题,答案与另一个已经发布的答案相同。我不相信这会导致它足够不同以保证另一个帖子

【讨论】:

  • 最后一个引号标记是怎么回事?我试着修复它。不确定它是否更好。
  • @simbabque:> 而不是-!谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多