更简洁的 breakOut 替代方案

6

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”无效。 - senia
是的,这就是我想要的。我也做了同样的事情,但是混淆了通用参数(在def中使用T,在代码中使用A),并且无法从编译器错误中找出问题所在。 - IttayD
1
@senia 可以把它作为答案吗? - Alexey Romanov
1
顺便说一下,去掉空括号会更好。 - IttayD
@IttayD:完成了。请看我的回答。 - senia
2个回答

4
这种方法不适用于StringMap。此外,这段代码需要使用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))

1

Senia的解决方案很棒。不幸的是,正如他所提到的,这对于MapString都不起作用。 下面是另一种替代方法(基于他的解决方案),可以实现:

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 [_]]。作为交换,您可以指定任何目标集合,而不管类型参数的数量(例如MapString)。
此外,如果选择,您仍然可以完全明确(类似于使用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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接