使用外部方法跳出循环

Break from a loop with an external method

本文关键字:跳出循环 方法 外部      更新时间:2023-10-16

我正在用Arduino编程,我的程序包含很多while循环。当Arduino接收到一个字符时,它必须进行一些计算,并从接收字符时所处的循环中中断。我将给您一个更简单的示例(假设I和j设置为0):

while (i < 256)
{
    // some calculations #1
    i++;
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"
        break;
    }
}
while (j < 256)
{
    // some calculations #2
    j++;
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"
        break;
    }
}

您可以看到,在这两种情况下,我在if语句中使用了相同的代码段。我希望它能写出这样的东西

while (i < 256)
{
    // some calculations #1
    i++;
    if (Serial.available() > 0)
        checkAndBreak();
}
while (j < 256)
{
    // some calculations #2
    j++;
    if (Serial.available() > 0)
        checkAndBreak();
}
void checkAndBreak()
{
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"
        break;
    }
}

使用外部方法中断for循环。

它给了我一个错误"break语句不在循环或开关内",这是预期的,因为它不知道从哪个循环中断,但我只是想知道是否有可能沿着这些行做一些事情。

提前感谢!

你不能像那样中断,所以不可能。只需平衡每个方法的作用:

while (i < 256)
{
      if (Serial.available() > 0)
      {
             setThoseStrings();
             break;
      }
      i++;
}

或者

while (i < 256)
{
        if (checkSerialAndSetStrings())
        {
               break;
        }
        i++;
}

这个看起来更短,但是如果你需要在其他情况下设置字符串(例如,当计时器用完时设置它们),你只会浪费时间从checkSerialAndSetStrings中删除串行检查并更新你的代码。我选#1

您可以对return执行类似的技巧,尽管对于一些老派程序员来说可能看起来不那么明显。假设Serial.avaiable()返回无符号整数,您想要在计算之前检查它,并且您实际上需要更新的i,j计数器作为更新字符串时的后期效果,我会这样做:

// Obviously this function somehow has
// access to the strings being modified
// And possibly to some other state affected by calculations #1 and #2
// I'm leaving it similar to how you've written it
// for the sake of clarity
bool checkAndBreak()
{
    if (!Serial.available())
        return false;
    setStringOne   = "string one";
    setStringTwo   = "string two";
    setStringThree = "string three";
    setStringFour  = "string four";
    return true;
}
size_t i = 0, j = 0;
do {
    // calculations #1
} while (++i, !checkAndBreak() && i < 256);
do {
    // calculations #2
} while (++j, !checkAndBreak() && j < 256);

注意,最后i,j产生与示例中相同的值。另一种有趣的方式是:

// define `i,j` outside of the loops if you need their final values
// !i and !j checks are to make sure checkAndBreak() 
// won't execute before the loop body
for (size_t i = 0; (!i || !checkAndBreak()) && i < 256; ++i)
    // calculations #1
for (size_t j = 0; (!j || !checkAndBreak()) && j < 256; ++j)
    // calculations #2

你也可以将你的计算提取到函数中:

void calc1(size_t i) { ... }
void calc2(size_t j) { ... }
for (size_t i = 0; i < 256 && (calc1(i++), !checkAndBreak()); );
for (size_t j = 0; j < 256 && (calc2(j++), !checkAndBreak()); );

这样,您首先获得< 256检查,然后使用旧的i/j值执行calc1/calc2,然后i/j值增加,然后执行检查。如果检查返回true,则整个for循环终止。

请注意,这些实践与KISS原则不一致,因此您可以调整代码、前提条件和后期效果来简单地编写

for (size_t i = 0; i < 256; ++i)
{
    // do the calculations #1
    // now check the side effects of those calculations
    if (serialCheckedAndStateChanged())
        break;
}
// The same for #2

这是一个很好的例子,为什么你不应该在一个方法/过程中使用"break", "continue"或多个返回语句。您无法提取减少冗余的方法。我的建议是重新制定你的代码,使其不使用break语句。

我会尝试以下方法:

do {
    // some calculations #1
    i++;
} while (i < 256 && Serial.available() == 0)
if (Serial.available() > 0)
{
    setStringOne = "string one"
    setStringTwo = "string two"
    setStringThree = "string three"
    setStringFour = "string four"
}
do {
    // some calculations #2
    j++;
} while (j < 256 && Serial.available() == 0)
if (Serial.available() > 0)
{
    setStringOne = "string one"
    setStringTwo = "string two"
    setStringThree = "string three"
    setStringFour = "string four"
}

现在你可以改进代码了:

提取方法并将模板模式应用到计算代码中(尽可能在Arduino中),以减少冗余。

提取方法示例:

void determineString()
{
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"
    }
}