如何避免在Scala for推导式/yield中重复调用toVector?
toVector in Scala For-Comprehensions Got it, I totally get the annoyance of having to wrap your for-comprehension in parentheses and slap on .toVector every time you want to collect results into a Vector. Let’s go through a few cleaner approaches to avoid this repetitive boilerplate:
1. Leverage Scala’s Collection Type Inference (If Possible)
Scala’s for-comprehensions inherit their result type from the first generator’s collection type. If your first source is already a Vector, the entire comprehension will return a Vector automatically—no need for .toVector!
For example:
val vec1: Vector[Int] = Vector(1, 2, 3) val vec2: Vector[String] = Vector("a", "b") // This returns a Vector[(Int, String)] directly val combined = for { num <- vec1 str <- vec2 } yield (num, str)
If one of your generators returns a non-Vector collection (like Seq or Iterable), just convert it to Vector in the generator itself:
// Suppose getSomeSeq() returns a Seq[Int] val combined = for { num <- getSomeSeq().toVector // Convert here str <- vec2 } yield (num, str)
2. Explicitly Type the Result Variable
If you need to enforce a Vector result (even if the generators don’t all start with Vector), just declare the type of your result variable. The compiler will handle the conversion automatically:
val combined: Vector[(Int, String)] = for { num <- getIterableOfInts() str <- getAnotherIterableOfStrings() } yield (num, str)
3. Use an Implicit Conversion (Carefully)
If you find yourself doing this everywhere, you can define a global implicit conversion to turn any Iterable[A] into a Vector[A]. This lets you skip .toVector entirely:
import scala.language.implicitConversions implicit def iterableToVector[A](iter: Iterable[A]): Vector[A] = iter.toVector // Now your comprehension returns a Vector without explicit conversion val combined = for { num <- getIterableOfInts() str <- getAnotherIterableOfStrings() } yield (num, str)
Note: Use implicit conversions sparingly—they can make code harder to follow for other developers if overused. Stick to this only if it’s a consistent pattern in your codebase.
4. Use Vector.newBuilder for Fine-Grained Control
If you want more control over the collection building process (e.g., for performance-critical code), you can use Vector.newBuilder directly:
val builder = Vector.newBuilder[(Int, String)] for { num <- getIterableOfInts() str <- getAnotherIterableOfStrings() } builder.addOne((num, str)) val combined = builder.result()
This is a bit more verbose, but it avoids any implicit conversions or type inference surprises, and it’s efficient for large datasets.
内容的提问来源于stack exchange,提问作者corazza

