Scala delegate import of implicit conversions

纵饮孤独 提交于 2019-12-22 10:00:00

问题


In Scala, how can I delegate the importing of implicit conversions into my scope, such that I don't have to have a big "environment" class which provides both library functions/values (for a DSL I am creating) as well as implicit conversions?

In short, can I move my implicit conversions from an object, and still have it imported when I write:

import MyDslEnvironment._

?

The goal of this is to make the importing and use of my framework simple and lightweight, in the sense that only a single import statement gives the user the needed functionality of my DSL/framework.

PS: Before anyone flames me - yes, I am aware of pitfalls and nastiness that can come from implicit conversions.


回答1:


My inclination would be to put the implicits in a package object.

Suppose that your work will be defined in the package com.acme.mydsl. Your source files are arranged in a directory hierarchy com > acme > mydsl. In the directory mydsl, define an object like so:

package com.acme; //we are in the mydsl dir, but note no mydsl in
                  //in the package declaration

package object mydsl {

   implicit def idioticallyStringsAre5( s : String ) : Int = 5

   //define other utilities that should be available within
   //the package or importable

}

Now, you can do this:

scala> import com.acme.mydsl._
import com.acme.mydsl._

scala> def sum( a : Int, b : Int ) = a + b
sum: (a: Int, b: Int)Int

scala> sum("hello", "there")
res0: Int = 10

By importing import com.acme.mydsl._, you got all the package-level function definitions, including the implicit conversion.

I really like package objects. It always seemed hokey in Java to have to make classes full of static members just for utility functions. Package objects serve as very elegant name spaces for these utilities, including implicit conversions.




回答2:


This can be achieved trivially using traits. Just define your implicit conversions in as many traits as is needed (to achieve modularity), and mix the traits in a single object (MyDslEnvironment). By example:

case class Foo( value: Int )
case class Bar( value: String )
object Baz {
  def test( foo: Foo, bar: Bar ) { println( foo + "," + bar ) }
}

trait ImplicitEnv1 {
  implicit def toFoo( value: Int ) = Foo( value )
}

trait ImplicitEnv2 {
  implicit def toBar( value: String ) = Bar( value )
}

object MyDslEnvironment extends ImplicitEnv1 with ImplicitEnv2

You can then do:

scala> import MyDslEnvironment._
import MyDslEnvironment._
scala> Baz.test( 123, "hello" )
Foo(123),Bar(hello)

You could in fact put all your code (Foo, Bar and Baz in my above example) inside traits, instead of just your implicit conversion (this may require to use self-type annotations). At which point you will have basically implemented one of the variants of the (in)famous cake pattern. See http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/



来源:https://stackoverflow.com/questions/12901554/scala-delegate-import-of-implicit-conversions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!