在Scala中,如何将隐式转换的导入委托给我的作用域,这样我就不必拥有一个大的“环境”类,它提供了库函数/值(对于我正在创建的DSL)以及隐式转换?
简而言之,我可以从对象移动隐式转换,并在写入时仍然导入它:
导入MyDslEnvironment ._
这样做的目的是使我的框架的导入和使用变得简单和轻量级,因为只有一个import语句为用户提供了我的DSL /框架所需的功能。
PS:在任何人为我开火之前 - 是的,我知道可能来自隐含转换的陷阱和肮脏。答案 0 :(得分:3)
这可以通过使用特征来实现。只需根据需要定义隐式转换(实现模块化),并在单个对象(MyDslEnvironment)中混合特征。例如:
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
然后你可以这样做:
scala> import MyDslEnvironment._
import MyDslEnvironment._
scala> Baz.test( 123, "hello" )
Foo(123),Bar(hello)
您实际上可以将所有代码(Foo
,Bar
和Baz
放在上面的示例中)放在特征中,而不仅仅是隐式转换(这可能需要使用自我 - 类型注释)。在这一点上,你将基本上实现(in)着名蛋糕模式的变体之一。
见http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/
答案 1 :(得分:3)
我的倾向是将隐含物放在包装物中。
假设您的工作将在com.acme.mydsl包中定义。您的源文件排列在目录层次结构com>中。 acme>看MyDSL。在目录mydsl中,定义一个如下对象:
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
}
现在,你可以这样做:
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
通过导入导入com.acme.mydsl._,您获得了所有包级别的函数定义,包括隐式转换。
我真的很喜欢包对象。在Java中,为了实用函数,必须使类充满静态成员。包对象充当这些实用程序的非常优雅的名称空间,包括隐式转换。