#scala
#scala
Вопрос:
breakOut хорош, но слишком многословен:
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(breakOut) : Array[(Int, Double, String)]
Я не хочу указывать тип элемента. Я хочу что-то вроде:
List(1, 2, 3).map{i => (i * 2, i / 2.0, i.toString)}(build[Array])
Я могу buildArray
легко написать, но тогда мне понадобятся buildSet, buildList и т.д. Итак, я хочу что-то общее.
Дополнительные баллы ( ;-)), если вы можете заставить это работать для Map (используя то же имя build
, а не build2 или buildMap)
Комментарии:
1. Это не то, что вы хотите, но я думаю, это лучшее, что вы можете получить. Это не будет работать для
String
илиMap
.2. Да, это то, чего я хотел. Я сделал то же самое, но перепутал общие параметры (использовал T в def и A в коде) и не смог разобраться с ошибкой компилятора.
3. @senia Может быть, сделать это ответом?
4. Кстати, было бы неплохо удалить пустые скобки.
Ответ №1:
Это не будет работать для String
или Map
. Также этот код требует 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))
Ответ №2:
Решение Senia отличное. К сожалению, как он упомянул, это не будет работать для Map
nor String
. Вот другая альтернатива (основанная на его решении), которая делает:
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
Это немного более подробно, потому что теперь вы не просто делаете build[Array]
, но build[Array[_]]
. В обмен вы получаете возможность указать любую целевую коллекцию, которую вы хотите, независимо от количества аргументов типа (таких как Map
и String
).
Кроме того, вы все равно можете быть полностью явными (аналогично использованию breakOut
), если вы решите:
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))
Все это с тем же синтаксисом (другими словами, с использованием того же имени build
, как вы просили)