如何在不牺牲性能的情况下保持良好的代码组织?

发布于 2024-10-12 05:22:43 字数 542 浏览 7 评论 0原文

我同意这样的观点:变量在使用之前不应被初始化。如果由使用该变量的代码来记住变量所代表的含义,则可以更容易地记住它,并且减少了变量在初始化和正确使用之间被误用的机会。

当该变量在一两个循环内使用时就会出现问题。然后,初始化成本会成倍增加,并且可能开始影响性能。

在 Perl 中(或一般情况下,视情况而定),它们是否有任何巧妙的小技术,允许您将变量的初始化放在循环中,但只在第一次传递时初始化?

我想到了类似的东西:

my $variable = undef;
while ($outer_loop) {
    while ($inner_loop) {
       $variable = $variable || 'initial_value'
    }
}

注意:这意味着 $variable 不会在循环内重新分配。

现在也许是我,但这似乎有点不优雅。

所以,这是我的问题:有没有一种更简洁的方法来做到这一点,或者我只需要克服自己并在代码组织上妥协,或者吸收上面的“不优雅”的解决方案?

I subscribe to the idea that variables shouldn't be initialized until right before you're going to use them. It makes it a lot easier to remember what a variable represents if it's by the code that will consume it, and it diminishes the chance that the variable will be misused between initialisation and proper use.

The problems comes when the use of that variable is inside a loop or two. Then, the cost of intialisation gets multiplied and it may begin to impact performance.

Within Perl (or generally, as appropriate), are their any neat little techniques that allow you to place the initialization of a variable within a loop, but such that it only gets initialized on the first pass?

I'd thought of something like:

my $variable = undef;
while ($outer_loop) {
    while ($inner_loop) {
       $variable = $variable || 'initial_value'
    }
}

NB: The implication is that $variable is not reassigned within the loop.

Now maybe it's me, but that seems a little inelegant.

So, here's my question: is there a neater way to do this, or do I just need to get overmyself and compromise on code organisation, or suck up that 'inelegant' solution above?

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

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

发布评论

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

评论(3

花期渐远 2024-10-19 05:22:43

要解决评论中的问题(变量在函数中计算):

  • 用于优化您想要的此类逻辑的标准技术称为(该函数的)记忆化。在其他方法中,Perl 有 Memoize 模块,或者您也可以自己做。

     使用 Memoize;
      memoize('slow_function');
      while ($outer_loop) {
          而($inner_loop){
              我的 $variable = Slow_function(arguments);
          }
      }
    
  • 此外,如果函数在整个循环中始终生成 100% 相同的值(根据设计),只需在循环之前的语句中初始化变量即可进行穷人记忆。

    如果你有一个3页长的循环(例如,与循环内部相比,循环之前的初始化太长,导致可读性问题),那么你遇到的编码问题不仅仅是初始化行的位置,并且需要首先重构您的代码。

    顺便说一句,如果您将变量放在循环之前唯一关心的是它会破坏“此变量仅用于此循环内”的可读性上下文,您可以通过以下任一方式轻松解决它:

    • 拥有详细记录的代码 - 相应地命名变量,或向初始化行添加注释,或两者兼而有之。

    • 或者,通过将变量命名为 my $default_value_for_next_loop = long_func(); ,并在循环内部实际创建一个从中初始化的本地循环变量: my $loop_var = $default_value_for_next_loop;

另外,就您自己的方法而言 ($variable = $variable || 'initial_value';);
我个人认为这绝对优雅且可读,但是!!!我非常确定它实际上比直接的 $variable = $default_value_for_next_loop; 执行更差,因为它有一个条件语句而不是直接赋值。但如果没有基准测试我就无法确定。

To address issues in your comment (the variable is computed in a function):

  • A standard technique for optimizing this sort of logic that you want is called memoization (of that function). Among other approaches, Perl has Memoize module, or you can do it yourself.

      use Memoize;
      memoize('slow_function');
      while ($outer_loop) {
          while ($inner_loop) {
              my $variable = slow_function(arguments);
          }
      }
    
  • Also, if the function is always producing 100% identical value (by design) throughout the loop, simply do a poor-mans memoization by initializing the variable in a statement prior to the loop.

    If you have a loop 3 pages long (e.g. so long that having the initialization before the loop is a readability problem compared to inside the loop), you have a bigger coding problem than just the location of the initialization line, and need to re-factor your code in the first place.

    As an aside, if your only concern with placing the variable before the loop is the fact that it destroys the readability context of "this variable is only for use inside this loop", you can easily solve it by either:

    • Having well documented code - either name the variable accordingly, or add a comment to initialization line, or both.

    • Or, by naming a variable something like my $default_value_for_next_loop = long_func(); , and inside the loop actually create a local loop variable initialized from that: my $loop_var = $default_value_for_next_loop;

Also, as far as your own approach ($variable = $variable || 'initial_value';);
I personally find that absolutely elegant and readable, BUT!!! I'm pretty sure that it actually performs worse than a straight-up $variable = $default_value_for_next_loop;, because it has a conditional statement instead of a straight assignment. But I can't be certain without benchmarking.

吃兔兔 2024-10-19 05:22:43

当在一个或两个循环内使用该变量时,就会出现问题。然后,初始化成本会成倍增加,并且可能开始影响性能。

是吗?你测量过吗?如果您的 $variable 适用于两个循环中的代码,那么我将按如下方式编写您的循环:

my $variable = 'initial_value';
while ($outer_loop) {
    while ($inner_loop) {
       # ...
    }
}

这样,读者就知道在以下部分中使用了 $variable代码,以及它的初始值是多少。在您的代码片段中,读者必须在循环深处的某个位置找到实际初始值。

这里不太可能出现性能问题,但如果这是一个关键因素,您应该始终测量性能。

The problems comes when the use of that variable is inside a loop or two. Then, the cost of intialisation gets multiplied and it may begin to impact performance.

Does it? Have you measured it? If your $variable applies to the code throughout both loops, then I would write your loop as follows:

my $variable = 'initial_value';
while ($outer_loop) {
    while ($inner_loop) {
       # ...
    }
}

That way, the reader knows that $variable is used in the following section of code, and what its initial value is. In your code snippet, the reader has to go find the actual initial value somewhere deep in the loop.

There is unlikely to be a performance problem here, but you should always measure the performance if that is a critical factor.

温暖的光 2024-10-19 05:22:43

我认为你的指导有点太过分了。阻止滥用变量的最佳方法是将其声明延迟到需要它之前。 (从而将其限制在尽可能小的词法范围内。)延迟初始化并不能防止误用;它只是为某人使用未定义的值、用自己的值抢占您的初始化或将您的变量用于完全不相关的目的创造了机会。

如果变量需要初始/默认值,则应尽可能将其作为声明的一部分来完成。这清楚地表明该变量具有起始值。

my $x = 1;
my $y = f($x);

延迟初始化意味着没有初始值。如果没有或者您无法提前确定它,那也没关系,但您稍后会通过偷偷添加 $var //= 'value' 来牺牲清晰度。

对于需要在循环迭代中保留其值的变量,您必须在循环外声明它们。有时我将循环包装在额外的块中,以防止这些变量泄漏到以下代码中:

{
    my $i = 5;
    for (1 .. 10) {
        say $i++;
    }
}

I think you're taking your guideline a little too far. The best way to stop misuse of a variable is to delay it's declaration until just before it's needed. (Thus limiting it to smallest possible lexical scope.) Delaying initialization doesn't prevent misuse; it just creates an opportunity for someone to use an undefined value, preempt your initialization with their own, or use your variable for a completely unrelated purpose.

If a variable requires an initial/default value, that should be done as part of the declaration if possible. This makes it clear that the variable has a starting value.

my $x = 1;
my $y = f($x);

Delaying the initialization implies that there isn't an initial value. That's fine if there isn't one or if you can't determine it ahead of time, but you sacrifice clarity by sneaking a $var //= 'value' in later.

For variables that need to retain their value across loop iterations you have to declare them outside the loop. Sometimes I wrap loops in an extra block to prevent those variables from leaking into the following code:

{
    my $i = 5;
    for (1 .. 10) {
        say $i++;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文