あなたの方法arraysToPoints
は余計です。次のように、メソッドの配列引数にバインドされたビューを使用してf
、のコンパニオン オブジェクトに変換を追加できますPoint
。
object Point {
implicit def arrayToPoint[A](a: Array[A])(implicit view: A => Double): Point =
Point(a(0), a(1))
}
case class Point(x: Double, y: Double)
def f[P](coords: Array[P])(implicit view: P => Point): Unit = coords.foreach { p =>
println(p: Point)
}
f(Array(Point(1, 2), Point(2, 3)))
f(Array(Array(1.0, 2.0), Array(3.0, 4.0)))
f(Array(Array(1, 2), Array(3, 4)))
Int
との両方の配列をカバーできるようにするために、メソッドDouble
にバインドされた 2 番目のビューを使用しました。arrayToPoint
そうしないと、 と に対して 2 つの別個の変換メソッドが必要にArray[Int]
なりArray[Double]
ます。
この定義は、「型として表示できるf
型の要素の配列を取る」と読むことができます。コンパイラがそのようなビューを探す 1 つの場所は、ターゲット型のコンパニオン オブジェクトです。これは、暗黙的なメソッドに適した場所です。P
Point
object Point
2 番目の可能性は、マグネット パターンを使用することです。のビューでポイントごとに変換する代わりにf
、単一のラッパー オブジェクトを一度に作成します。これは少しきれいで、大きな配列の場合、直接Array[Double]
引数のペナルティを最小限に抑えます (ラッパーを一度インスタンス化するだけで、ビュー関数を呼び出す必要がなくなるため)。arrayToPoint
配列要素の型A
が再び として表示できる場合は常に使用されDouble
ます。Double
これはもちろんそれ自体にも当てはまりますが、これはScala が数値の拡大と呼んでいるものと見なすInt
ことDouble
もできます (たとえば、val x: Double = 33
整数33
は暗黙的に double に「拡大」されます)。
object Points {
implicit def direct(a: Array[Point]): Points =
new Points {
val peer = a
}
implicit def indirect[A](a: Array[Array[A]])(implicit view: A => Double): Points =
new Points {
lazy val peer = a.map { c => Point(c(0), c(1)) }
}
}
trait Points {
def peer: Array[Point]
}
def f(coords: Points): Unit = coords.peer.foreach(println)
これは、コンパニオン オブジェクトで、引数 type から特殊な magnet type への暗黙的なメソッドを探しますPoints
。メソッドが呼び出されないlazy val
場合に実際の変換アクションを保存できるように、非直接配列に使用します。peer