问题
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