Scala中如何实现类似Java Predicate的or组合(无外部库)
Great question! Since Scala doesn't have a dedicated Predicate interface like Java—relying instead on Function1[A, Boolean] (aka A => Boolean) for similar logic—the most idiomatic and performant way to add or (and related) composition methods is to use Scala's implicit extension methods (or Scala 3's native extension syntax). This avoids writing repetitive lambda boilerplate while staying true to Scala's functional style.
Implementation Options
1. Scala 2: Implicit Value Class Extension
For Scala 2, we can use an implicit value class (extending AnyVal) to avoid runtime overhead while adding methods to A => Boolean:
object PredicateCombinators { implicit class PredicateOps[A](private val self: A => Boolean) extends AnyVal { // Mimics Java's Predicate.or() def or(other: A => Boolean): A => Boolean = a => self(a) || other(a) // Bonus: Add and() to match Java's Predicate.and() def and(other: A => Boolean): A => Boolean = a => self(a) && other(a) // Bonus: Add negate() for Predicate.negate() equivalent def negate: A => Boolean = a => !self(a) } }
2. Scala 3: Native Extension Syntax
Scala 3 simplifies extensions with dedicated syntax, no need for implicit classes or AnyVal (the compiler handles optimization automatically):
extension [A](self: A => Boolean) def or(other: A => Boolean): A => Boolean = a => self(a) || other(a) def and(other: A => Boolean): A => Boolean = a => self(a) && other(a) def negate: A => Boolean = a => !self(a)
How to Use It
Once you've defined the extensions, import them (if needed) and use them just like Java's Predicate methods:
// Import the extensions (Scala 2 only; Scala 3 extensions can be in scope directly) import PredicateCombinators._ // Define your base predicates val isEven: Int => Boolean = _ % 2 == 0 val isPositive: Int => Boolean = _ > 0 // Combine them with or() val isEvenOrPositive = isEven.or(isPositive) // Test the combined predicate println(isEvenOrPositive(2)) // Output: true println(isEvenOrPositive(-1)) // Output: false println(isEvenOrPositive(3)) // Output: true
Why This Is the Optimal Approach
- Idiomatic Scala: Extensions are the standard way to add functionality to existing types without modifying their source code, aligning with Scala's "open extension" philosophy.
- Zero Overhead: Using
AnyVal(Scala 2) or native extensions (Scala 3) ensures no extra object wrapping at runtime—performance is identical to writing the lambda manually. - Readable & Reusable: The
or()method reads naturally, just like Java'sPredicate.or(), and you can reuse the extension across your codebase without repeating lambda logic. - Extensible: You can easily add more methods (like
xor()) to match additional predicate composition needs.
内容的提问来源于stack exchange,提问作者senjin.hajrulahovic

