Scala中如何惯用定义AnyVal类型的AnyRef等效类型ARE[T]?
当然有Scala惯用的解决方案啦,不用写一堆重载方法,**类型类(Type Class)**就是处理这种类型映射场景的绝佳手段,咱们一步步来实现你要的ARE[T]:
用类型类实现ARE[T]的Scala惯用方案
1. 定义核心类型类ARE
首先我们定义一个类型类,用来描述T到它的AnyRef等效类型的映射规则:
trait ARE[T] { // 定义T对应的AnyRef等效类型 type Out <: AnyRef // 将T类型的值包装为Out类型(AnyRef) def wrap(value: T): Out // 将Out类型的值解包回T类型 def unwrap(wrapped: Out): T }
这个类型类的核心是Out类型成员,它会绑定到T对应的AnyRef类型,同时提供双向转换的方法。
2. 为所有AnyRef类型提供通用实例
对于本身就是AnyRef的类型,我们直接返回它自身,写一个通用的implicit实例即可:
implicit def areForAnyRef[T <: AnyRef]: ARE[T] = new ARE[T] { type Out = T def wrap(value: T): T = value def unwrap(wrapped: T): T = wrapped }
这样所有String、List这类AnyRef子类都会自动适配这个实例,不需要额外编写代码。
3. 为AnyVal类型提供boxed实例
对于每个AnyVal基本类型,我们绑定到对应的java.lang.*boxed类型,比如Int对应java.lang.Integer,Boolean对应java.lang.Boolean:
// Int -> java.lang.Integer implicit val areForInt: ARE[Int] = new ARE[Int] { type Out = java.lang.Integer def wrap(value: Int): java.lang.Integer = value.asInstanceOf[java.lang.Integer] def unwrap(wrapped: java.lang.Integer): Int = wrapped } // Boolean -> java.lang.Boolean implicit val areForBoolean: ARE[Boolean] = new ARE[Boolean] { type Out = java.lang.Boolean def wrap(value: Boolean): java.lang.Boolean = value.asInstanceOf[java.lang.Boolean] def unwrap(wrapped: java.lang.Boolean): Boolean = wrapped } // 同理实现其他AnyVal类型的实例: // Short -> java.lang.Short,Long -> java.lang.Long // Float -> java.lang.Float,Double -> java.lang.Double // Char -> java.lang.Character,Byte -> java.lang.Byte
这里用asInstanceOf做转换是安全的,因为Scala会自动处理基本类型和boxed类型的装箱/拆箱。
4. 编写使用类型类的方法
现在我们可以定义你需要的foo方法,利用implicit参数自动获取对应的ARE实例:
def foo[A](value: A)(implicit ev: ARE[A]): ev.Out = ev.wrap(value)
调用的时候编译器会自动匹配对应的实例,完全符合你的需求:
// String是AnyRef,直接返回String val strResult: String = foo("Hello Scala!") // Int会被装箱为java.lang.Integer val intResult: java.lang.Integer = foo(42) // Boolean会被装箱为java.lang.Boolean val boolResult: java.lang.Boolean = foo(true)
额外说明
- 编译时检查:如果某个AnyVal类型没有对应的
java.lang.*类型(这种情况在Scala的标准AnyVal类型里不存在,但如果是自定义AnyVal类型的话),编译器会因为找不到对应的AREimplicit实例而直接报错,完美满足你要求的编译错误触发条件。 - 扩展性:如果以后需要支持自定义的类型,只需要添加对应的
ARE实例即可,不需要修改原有方法,符合开闭原则。
内容的提问来源于stack exchange,提问作者Sim
相关产品推荐
相关产品推荐

