0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

暗黙の変換

慎重に使用します。

「暗黙の変換」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

暗黙の変換とは

暗黙の変換とは、コンパイラーが必要としたときに、ある型の値を別の型へ自動的に変換する仕組みです。APIを便利にできますが、何が起きているかが隠れるため、注意して使う必要があります。

object Main {
  import scala.language.implicitConversions
  implicit def intToString(x: Int): String = s"number-$x"
  def main(args: Array[String]): Unit = {
    val s: String = 42
    println(s)
  }
}

コンパイラーによる利用方法

値の型が期待される型と一致しない場合、コンパイラーは不一致を解消する暗黙の変換を探し、それを暗黙に挿入します。

object Main {
  import scala.language.implicitConversions
  implicit def doubleToInt(d: Double): Int = d.toInt
  def addTen(x: Int): Int = x + 10
  def main(args: Array[String]): Unit = {
    println(addTen(3.9))
  }
}

機能を有効にする

暗黙の変換を定義するにはscala.language.implicitConversionsをインポートする必要があります。インポートしないとコンパイラーが警告します。これは使いすぎを防ぐための意図的な制約です。

object Main {
  import scala.language.implicitConversions
  case class Celsius(value: Double)
  implicit def doubleToCelsius(d: Double): Celsius = Celsius(d)
  def describe(c: Celsius): String = s"${c.value} C"
  def main(args: Array[String]): Unit = {
    println(describe(36.6))
  }
}

追加メソッドのためのラッピング(旧方式)

拡張メソッドが登場する前は、既存の型にメソッドを「追加」する方法として、ラッパークラスへの暗黙の変換が使われていました。いわゆるpimp-my-libraryパターンです。

object Main {
  import scala.language.implicitConversions
  class RichInt2(x: Int) {
    def squared: Int = x * x
  }
  implicit def toRich(x: Int): RichInt2 = new RichInt2(x)
  def main(args: Array[String]): Unit = {
    println(5.squared)
  }
}

危険性:気付きにくい予期せぬ動作

変換は呼び出し側から見えないため、原因を追跡しにくい不可解な動作やバグを引き起こす可能性があります。タイプミスであっても、誤って変換が発生することでコンパイルできてしまう場合があります。

object Main {
  import scala.language.implicitConversions
  implicit def boolToInt(b: Boolean): Int = if (b) 1 else 0
  def main(args: Array[String]): Unit = {
    val total = true + 4 // surprising! becomes 1 + 4
    println(total)
  }
}

明示的な変換を優先する

多くの場合、暗黙の変換ではなく、通常の名前付きメソッドを使うほうが安全です。コードは長くなりますが、読み手にとって明確になります。

object Main {
  case class Celsius(value: Double)
  def fromDouble(d: Double): Celsius = Celsius(d)
  def main(args: Array[String]): Unit = {
    val c = fromDouble(20.5)
    println(c)
  }
}

Scala 3:Conversion型クラス

Scala 3では、given Conversion[A, B]インスタンスによって変換を明示的に定義します。意図がより明確になりますが、引き続き言語機能のインポートが必要です。

import scala.language.implicitConversions

object Main:
  given Conversion[Int, String] = (x: Int) => s"val-$x"
  def main(args: Array[String]): Unit =
    val s: String = 7
    println(s)

変換は1回だけ適用される

コンパイラーが一度に適用する暗黙の変換は最大1つです。不一致を解消するために2つの変換を連鎖させることはないため、予期せぬ動作が抑えられます。

object Main {
  import scala.language.implicitConversions
  implicit def intToStr(x: Int): String = x.toString
  def needString(s: String): Int = s.length
  def main(args: Array[String]): Unit = {
    println(needString(12345))
  }
}

変換が見つかる場所

他の暗黙の値と同様に、変換はローカルスコープ、インポート、コンパニオンオブジェクトから解決されます。名前の明確なインポートにまとめると、変換の存在を見えるようにできます。

object Conversions:
  import scala.language.implicitConversions
  implicit def strToLen(s: String): Int = s.length

object Main:
  import Conversions._
  def main(args: Array[String]): Unit =
    val n: Int = "hello"
    println(n)

変換が適切な場合

Javaの型との相互運用、数値の拡張変換ヘルパー、ライブラリとの境界などが正当な用途です。それ以外では、拡張メソッドまたは明示的な関数を優先してください。

object Main {
  import scala.language.implicitConversions
  case class Meters(v: Double)
  implicit def metersToDouble(m: Meters): Double = m.v
  def main(args: Array[String]): Unit = {
    val d: Double = Meters(3.5)
    println(d * 2)
  }
}

基本原則

変換が発生していることをコードから読み手が判断できないなら、それは警告サインです。暗黙の変換は、拡張メソッドや明示的な呼び出しを検討した最後に選択してください。

object Main {
  // Explicit and obvious - usually better
  case class Price(cents: Int)
  def toDollars(p: Price): Double = p.cents / 100.0
  def main(args: Array[String]): Unit = {
    println(toDollars(Price(1599)))
  }
}

クイックチェック

暗黙の変換の主なリスクは何ですか。

まとめ

暗黙の変換とその注意点について学びました。

  • 型が一致しない場合、一方の型を別の型に自動変換します
  • import scala.language.implicitConversions が必要です
  • Scala 3 では given Conversion[A, B] を使用します
  • 一度に適用される変換は 1 つだけです
  • 使用は控えめにし、拡張メソッドまたは明示的な呼び出しを優先します

よくある質問

「暗黙の変換」レッスンは無料ですか?

はい。「暗黙の変換」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。

「暗黙の変換」で何を学びますか?

慎重に使用します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「暗黙の変換」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 暗黙のパラメーター
  2. Scala 3 の given/using
  3. 暗黙の変換
  4. 拡張メソッド
← Scala for Backend Engineering & Functional Programmingに戻る