Scala:不可参数化提取器的替代解决方案
解决Scala提取器无法传显式参数的替代方案
我懂你现在的困扰:Scala标准提取器的unapply只能用隐式参数,没法直接传key这类显式参数,导致你要写一堆重复的case语句。针对你需要把width和width multiplied by x这类可组合的字符串归为同一key分类的需求,这里有几个简洁实用的替代方案:
方案1:带参数的提取器实例(最直观的复用方式)
我们可以定义一个通用的提取器类,把key和目标匹配字符串(比如"width")作为构造参数,让unapply方法基于这些参数实现匹配逻辑。这样你只需要为每个维度创建一个实例,就能在模式匹配里轻松复用了。
// 通用提取器类:接收key和基础名称,匹配单独名称或"名称 multiplied by x"格式 class DimensionExtractor(key: String, baseName: String) { def unapply(input: String): Option[(String, Option[String])] = { val basePattern = s"^$baseName$$".r val multipliedPattern = s"^$baseName multiplied by (\\w+)$$".r input match { case basePattern() => Some((key, None)) case multipliedPattern(x) => Some((key, Some(x))) case _ => None } } } // 为每个维度预定义提取器实例 object DimensionExtractors { val Width = new DimensionExtractor("w", "width") val Height = new DimensionExtractor("h", "height") val Length = new DimensionExtractor("l", "length") // 新增维度只需在这里加一行 } // 实际使用示例 import DimensionExtractors._ def classifyInput(input: String): String = input match { case Width(key, None) => s"Type: width, Key: $key" case Width(key, Some(x)) => s"Type: width (multiplied by $x), Key: $key" case Height(key, None) => s"Type: height, Key: $key" case Height(key, Some(x)) => s"Type: height (multiplied by $x), Key: $key" case Length(key, None) => s"Type: length, Key: $key" case Length(key, Some(x)) => s"Type: length (multiplied by $x), Key: $key" case _ => "Unknown input" }
这个方案把匹配逻辑集中在一处,新增维度只需要创建新实例,不用重复写正则和判断逻辑,非常适合你有大量可组合翻译内容的场景。
方案2:辅助函数+模式守卫(轻量精简版)
如果你不想创建太多提取器实例,可以把匹配逻辑封装成辅助函数,结合模式守卫和映射表来减少重复代码:
object DimensionMatcher { // 判断输入是否匹配指定维度格式 def isDimension(input: String, baseName: String): Boolean = { val basePattern = s"^$baseName$$".r val multipliedPattern = s"^$baseName multiplied by (\\w+)$$".r input match { case basePattern() | multipliedPattern(_) => true case _ => false } } // 维度名称到key的映射表 val nameToKey = Map( "width" -> "w", "height" -> "h", "length" -> "l" ) } // 使用示例 import DimensionMatcher._ def classifyInput(input: String): String = { nameToKey.keys.find(name => isDimension(input, name)) match { case Some(name) => val key = nameToKey(name) input match { case s"$name multiplied by $x" => s"Type: $name (multiplied by $x), Key: $key" case _ => s"Type: $name, Key: $key" } case None => "Unknown input" } }
这个方案更轻量,用字符串插值和映射表替代重复的case语句,适合维度数量不算特别多的场景。
方案3:Scala 3专属:枚举+提取器(类型安全首选)
如果你用的是Scala 3,可以利用枚举类的特性,把每个维度的key和匹配逻辑封装在枚举成员里,既保证类型安全,代码又整洁:
enum Dimension(val key: String, val baseName: String): case Width extends Dimension("w", "width") case Height extends Dimension("h", "height") case Length extends Dimension("l", "length") def unapply(input: String): Option[Option[String]] = val basePattern = s"^$baseName$$".r val multipliedPattern = s"^$baseName multiplied by (\\w+)$$".r input match case basePattern() => Some(None) case multipliedPattern(x) => Some(Some(x)) case _ => None // 使用示例 def classifyInput(input: String): String = input match { case Dimension.Width(None) => s"Type: width, Key: ${Dimension.Width.key}" case Dimension.Width(Some(x)) => s"Type: width (multiplied by $x), Key: ${Dimension.Width.key}" case Dimension.Height(None) => s"Type: height, Key: ${Dimension.Height.key}" case Dimension.Height(Some(x)) => s"Type: height (multiplied by $x), Key: ${Dimension.Height.key}" case Dimension.Length(None) => s"Type: length, Key: ${Dimension.Length.key}" case Dimension.Length(Some(x)) => s"Type: length (multiplied by $x), Key: ${Dimension.Length.key}" case _ => "Unknown input" }
Scala 3的枚举天然支持为每个成员添加属性和方法,把key、维度名称、匹配逻辑牢牢绑定在一起,维护起来特别方便。
内容的提问来源于stack exchange,提问作者alpinist
相关产品推荐
相关产品推荐

