生而为人

程序员的自我修养

0%

[toc]

待整理

什么版本的scala sdk collection中包含breakOut

breakOut 是 Scala 2.8 标准库 scala.collection 包中的一个方法-3,在 Scala 2.13 中被移除–。

下面整理了 breakOut 的版本支持情况,并提供了从 2.13 开始的替代方案。


breakOut 的版本变迁

Scala 版本 breakOut 支持状态 备注
2.8 至 2.12 可用 核心功能,需要 import scala.collection.breakOut-3
2.13 已移除 官方推荐使用 .view + .to(Collection) 组合替代--14
3.x 已移除 无此方法,需使用替代方案

💡 breakOut 是什么?

breakOut 是一个基于 CanBuildFrom 机制的工具,作用是在集合类型转换时避免创建不必要的中间集合,从而提升性能并简化代码。

例如,将 List[String] 直接转为 Map[Int, String],原本需要生成中间 List[(Int, String)] 再调用 .toMap。使用 breakOut 可以一步完成:

scala

复制下载

1
2
3
import scala.collection.breakOut
val m: Map[Int, String] = List("London", "Paris").map(x => (x.length, x))(breakOut)
// m: Map(6 -> London, 5 -> Paris)

在 2.8 至 2.12 版本中,这种方式有效避免了中间集合的开销,并让集合类型推断更为灵活-3


🔁 从 2.13 开始的替代方案

从 2.13 起,CanBuildFromBuildFrom 替代,标准库推荐以下方式实现类似效果:

替代方式 示例代码 特点
.view.map(...).to(...) List("London", "Paris").view.map(x => (x.length, x)).to(Map) 官方推荐,懒加载中间步骤,清晰高效
.iterator.map(...).to(...) List("London", "Paris").iterator.map(x => (x.length, x)).to(Map) 与视图类似,但迭代器不可重用

两种方式都能避免创建中间集合,性能与原先的 breakOut 相当。其中视图可以被多次重用,而迭代器在使用一次后就失效了-14

对于需要一步完成类型转换的场景,优先使用 .view.map(...).to(...) 即可。


💎 总结

  • 版本支持breakOutScala 2.8 ~ 2.12 中可用,2.13 起被移除。
  • 替代方案:升级到 2.13+ 后,改用 .view.map(...).to(Collection)
  • 核心目标:避免中间集合,提升转换性能与代码可读性。

[toc]

Solutions

如果想在scala里面保存一个类似于模板的类,里面规定了继承某个trait需要实现的方法,但是这个方法的返回值和参数是不定的,有什么方式实现吗

在 Scala 中,你可以利用泛型(type parameters)抽象类型成员(abstract type members) 来定义一个“模板” trait,其中方法的参数类型和返回值类型可以留给子类去具体指定。这两种方式都能实现你的需求,下面分别介绍。


方案一:泛型 trait(类型参数)

这是最直接的方式。在 trait 上声明类型参数,然后在抽象方法中使用这些参数。

scala

复制下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义一个模板 trait,其中 F 是参数类型,R 是返回值类型
trait Processor[F, R] {
def process(input: F): R
}

// 具体实现:处理 String 返回 Int
class StringLengthProcessor extends Processor[String, Int] {
override def process(input: String): Int = input.length
}

// 具体实现:处理 (Int, Int) 返回 Boolean
class SumEvenProcessor extends Processor[(Int, Int), Boolean] {
override def process(input: (Int, Int)): Boolean = (input._1 + input._2) % 2 == 0
}

优点:清晰、类型安全,子类只需指定具体类型。
缺点:如果多个方法共享相同的类型参数,所有方法必须统一使用这些参数。如果你希望不同方法有不同的参数/返回类型,可以为每个方法单独定义类型参数。


方案二:抽象类型成员(Abstract Type Members)

将类型参数内化为 trait 的抽象成员,子类通过 type 关键字来具体化。

scala

复制下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
trait Processor {
type Input
type Output
def process(input: Input): Output
}

// 子类实现
class StringLengthProcessor extends Processor {
override type Input = String
override type Output = Int
override def process(input: Input): Output = input.length
}

// 另一种实现
class SumEvenProcessor extends Processor {
override type Input = (Int, Int)
override type Output = Boolean
override def process(input: Input): Output = (input._1 + input._2) % 2 == 0
}

优点:有时更符合直觉,尤其是当类型与类紧密相关时。
缺点:在外部使用抽象类型成员时,类型推断可能不如泛型方便(需要使用 # 投影或路径依赖类型)。


方案三:高阶类型(Higher-Kinded Types)—— 适用于参数化容器

如果你的方法需要接收一个类型构造器(例如 List[_]Future[_]),可以用高阶类型。

scala

复制下载

1
2
3
4
5
6
7
trait Wrapper[F[_]] {
def wrap[A](value: A): F[A]
}

class ListWrapper extends Wrapper[List] {
override def wrap[A](value: A): List[A] = List(value)
}

方案四:使用元组或 HList 处理不定数量的参数

如果“参数是不定的”指的是参数个数不定(而非类型不定),可以用元组(固定个数但类型可不同)或 HList(如 Shapeless)。元组是最简单的方案:

scala

复制下载

1
2
3
4
5
6
7
8
trait Processor[Args, R] {
def process(args: Args): R
}

// 处理两个参数:Int 和 String,返回 Boolean
class Example extends Processor[(Int, String), Boolean] {
override def process(args: (Int, String)): Boolean = args._1 > 0 && args._2.nonEmpty
}

如果需要真正的变长参数(varargs),可以定义方法参数为 Seq[A]

scala

复制下载

1
2
3
trait SumProcessor[A, R] {
def process(args: A*): R // 注意:Scala 中的 varargs 实际上是 Seq[A]
}

但注意:A* 在 trait 中定义时,实现类必须同样使用 A*,这可能会带来一些限制。


推荐方案总结

需求 推荐方案
单个方法,参数和返回值类型可变 泛型 trait(方案一)
多个方法共享同一组类型 泛型 trait抽象类型成员
类型与类实例绑定(路径依赖) 抽象类型成员(方案二)
参数个数不定但类型相同 Seq[A]A*
参数个数不定且类型不同 元组(TupleX)或 Shapeless HList

绝大多数场景下,方案一(泛型 trait) 足够简洁且强大,建议优先使用。

如果你需要更具体的代码示例(比如结合隐式参数、上下界等),可以补充说明你的实际应用场景,我会给出更贴合的例子。

noclassdeffounderror 解决

ClassNotFoundException和NoClassDefFoundError的区别

实习杂记(27):如何解决Java.lang.NoClassDefFoundError

system.currenttimemillis() 耗时

System.currentTimeMillis的性能真有如此不堪吗?

缓慢的System.currentTimeMillis() - 疑问号

关于时间格式 2016-08-9T10:01:54.123Z 20160809100154.123Z 处理方法

编码

Base64.getMimeDecoder().decode(data)
Base64.getDecoder().decode(data);
区别

Base64 Encoding: Illegal base64 character 3c

疑问

  1. URLDecoder.decode作用
  2. 为什么不允许使用java静态构造函数

1
2
3
import scala.jdk.CollectionConverters._

import scala.collection.JavaConverters._ //如果scala SDK version <= 2.12
1
2
import scala.collection.mutable
import scala.collection.immutable

List

底层实现是单向链表,所以慎用通过index的遍历方式,因为每次都要从头节点开始查。IndexedSeq可以使用

1
2
3
for (i until nums.lenght) {
println(nums(i))
}

如果需要遍历List,又同时需要获取到index,可以改用迭代或zipWithIndex

1
2
3
4
5
6
7
// 迭代


// zipWithIndex
for ((value, index) <- nums.zipWithIndex) {
...
}

IndexedSeq 的实现主要包括:

Array

当输出在sleep之后时,无法打印

怀疑原因是因为线程被挂起,无法继续执行,但为什么每个线程都无法被唤醒?需要看下唤醒逻辑

1
2
Thread.sleep(2000);
System.out.println("orderInfo:" + orderInfo);

502错误

有可能是因为有人在进行远程调试

空指针可能情况

基本类型的值为null