Выход из цикла с помощью внешнего метода



Я программирую с помощью 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;
}
}


Чтобы прервать цикл с помощью внешний метод.



Это дает мне ошибку "break statement not within loop or switch", которая ожидается, так как он не знает, из какого цикла разорвать, но мне просто интересно, можно ли сделать что-то в этом роде.



Заранее спасибо!

615   3  

3 ответов:

Ты не можешь так сломаться, так что ни за что. Просто сбалансируйте то, что делает каждый метод:

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, затем calc1/calc2 выполняются со старыми значениями i/j, затем значение i/j увеличивается, а затем выполняется проверка. Если проверка возвращает true, весь цикл for завершается.

Остерегайтесь, что эти практики не согласуются с принципом поцелуя, поэтому вы можете настроить свой код, предварительные условия и постэффекты просто напишите

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" или несколько операторов return в методе/процедуре. Вы не можете извлечь методы для уменьшения избыточности. Мой совет-переформулировать ваш код, чтобы работать без брейк-операторов.

Я бы попробовал следующий подход:

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"
}

Теперь вы можете улучшить код:

Извлеките методы и примените шаблон pattern к коду вычисления (насколько это возможно в Arduino), чтобы уменьшить избыточность.

Пример извлеченного метода:

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

Comments

    Ничего не найдено.