【Scala】Scala ~ break / continue ~

■ はじめに

https://dk521123.hatenablog.com/entry/2023/01/24/000000

で述べた通り、Scala には、 break / continue が基本使用しない。
そこでどうするかを纏める

目次

【1】break / continue の代替案
 1)break の代替案
 2)continue の代替案
【2】サンプル
 1)お題:break/continueがあるJavaコードを書き換える
【3】別解1:再帰を使う
【4】別解2:scala.util.control.Breaks.breakを使う
 1)scala.util.control.Breaks.break
 2)ContinueをBreakで置き換える

【1】break / continue の代替案

1)break の代替案

* Boolean変数(フラグ)で置き換える 

2)continue の代替案

* if 文で置き換える

【2】サンプル

1)お題:break/continueがあるJavaコードを書き換える

https://paiza.io/en/languages/online-java-compiler

public class Main {
    public static void main(String[] args) throws Exception {
      String[] targets = {"java", "c", "-skip", "scala", "-skip", "Done"};
      int i = 0;
      boolean isFound = false;
      while (i < targets.length) {
          if (targets[i].startsWith("-")) {
              i = i + 1;
              continue;
          }
          if (targets[i].equals("scala")) {
              isFound = true;
              break;
          }
          i = i + 1;
      }
      // Done : i=3, isFound=true
      System.out.println("Done : i=" + i + ", isFound=" + isFound);
    }
}

Scalaコード

// あくまで例
object Hello {
  def main(args: Array[String]): Unit = {
    val targets = Array("java", "c", "-skip", "scala", "-skip", "Done")
    var i = 0
    var isFound = false
    while (i < targets.length && !isFound) {
      if (!targets(i).startsWith("-")) {
        if (targets(i).equals("scala")) {
          isFound = true
        }
      }
      // Javaと同じ結果にしたい場合、
      // if文で制御するがそうじゃない場合はこのIF文は不要
      if (!isFound) {
        i = i + 1
      }
    }
    println("Done : i=" + i + ", isFound=" + isFound)
  }
}

【3】別解1:再帰を使う

object Hello {
  def main(args: Array[String]): Unit = {
    val targets = Array("java", "c", "-skip", "scala", "-skip", "Done")
    def getIndexIfFound(targets: Array[String], index: Int, target: String): Int = {
      if (targets.length <= index) {
        -1
      } else if (targets(index).equals(target)) {
        index
      } else {
        getIndexIfFound(targets, index + 1, target)
      }
    }
    val index = getIndexIfFound(targets, 0, "scala")
    if (index != -1) {
      println("Done : index=" + index + ", target=" + targets(index))
    } else {
      println("Done : index=" + index)
    }
  }
}

【4】別解2:scala.util.control.Breaks.breakを使う

1)scala.util.control.Breaks.break

* scala.util.control.Breaks を利用
* Scala 2.8から使用可能

http://simplesandsamples.com/break.scala.html

サンプル

import scala.util.control.Breaks._

object  Hello {
  def main(args: Array[String]) {
    var count = 0
    breakable {
      println("Start")
      while (true) {
        count = count + 1
        println(s"count = ${count}")
        if(count == 5) {
          break
        }
      }
    }
    println(s"Done. count=${count}")
  }
}

[出力結果]

Start
count = 1
count = 2
count = 3
count = 4
count = 5
Done. count=5

2)ContinueをBreakで置き換える

* Scala には、Continue文はないが、前述した「1)break」を
 ループ内にすることで、Continue文と同じになる
 => 正直、いけてない、、、
 => breakableを使うことによりインデントも増えるし、可読性は下がるし、、、

https://stackoverflow.com/questions/62805222/continue-in-scala-for-loops

サンプル

import scala.util.control.Breaks._

object  Hello {
  def main(args: Array[String]) {
    println("Start")
    for(i <- 1 to 10) {
      println(s"i = ${i}")
      breakable {
        if (i % 2 != 0) {
          // break out of the 'breakable', continue the outside loop
          break
        }
        println(s"*****${i}*****")
      }
    }
    println(s"Done.")
  }
}

出力結果

Start
i = 1
i = 2
*****2*****
i = 3
i = 4
*****4*****
i = 5
i = 6
*****6*****
i = 7
i = 8
*****8*****
i = 9
i = 10
*****10*****
Done.

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / 繰り返し ~
https://dk521123.hatenablog.com/entry/2023/01/24/000000