Alternative to breakOut, which is less detailed

breakOut is nice, but too verbose:

List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(breakOut) : Array[(Int, Double, String)] 

I do not want to indicate the type of element. I need something like:

  List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array]) 

I can write buildArray easily, but then I need buildSet, buildList, etc. So I want something in common.

Extra points (;-)) if you can make it work for the Map (using the same name build , not build2 or buildMap)

+6
source share
2 answers

This will not work for String or Map . Also, this code requires scala.language.higherKinds :

 import collection.generic.CanBuildFrom import collection.breakOut class Build[To[_]] def build[To[_]] = new Build[To] implicit def buildToCbf[From, T, To[_]](b: Build[To]) (implicit cbf: CanBuildFrom[Nothing,T,To[T]]): CanBuildFrom[From,T,To[T]] = collection.breakOut List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array]) //res0: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3)) 
+4
source

Seny's decision is great. Unfortunately, as he said, this will not work for Map and String . Here is another alternative (based on its solution) that does:

 import collection.generic.CanBuildFrom import collection.breakOut class Build[To] def build[TargetSuperType] = new Build[TargetSuperType] implicit def buildToCbf[From, T, TargetSuperType, To<:TargetSuperType](b: Build[TargetSuperType]) (implicit cbf: CanBuildFrom[Nothing,T,To]): CanBuildFrom[From,T,To] = collection.breakOut List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array[_]]) //res0: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3)) List(1, 2, 3).map{i => (i * 2, i.toString)}(build[Map[_,_]]) //res1: scala.collection.immutable.Map[Int,String] = Map(2 -> 1, 4 -> 2, 6 -> 3) List('a', 'b', 'c').map(_.toUpper)(build[String]) //res2: String = ABC 

This is a bit more detailed, because now you are not just build[Array] , but build[Array[_]] . In return, you get the opportunity to specify any target collection that you want, regardless of the number of type arguments (for example, Map and String ).

In addition, you can be completely explicit (similar to using breakOut ) if you decide:

 scala> List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array[(Int, Double, String)]]) res3: Array[(Int, Double, String)] = Array((2,0.5,1), (4,1.0,2), (6,1.5,3)) 

Everything with the same syntax (in other words, using the same build name as you requested)

+1
source

Source: https://habr.com/ru/post/971851/


All Articles