Выход из цикла с помощью внешнего метода
Я программирую с помощью 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", которая ожидается, так как он не знает, из какого цикла разорвать, но мне просто интересно, можно ли сделать что-то в этом роде.
Заранее спасибо!
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