在 Scala 中,我如何将隐式转换的导入委托给我的范围,这样我就不必拥有一个大的“环境”类,它既提供库函数/值(对于我正在创建的 DSL)也提供隐式转换?
简而言之,我可以从一个对象中移动我的隐式转换,并在我编写时仍然导入它:
导入 MyDslEnvironment._
?
这样做的目的是使我的框架的导入和使用变得简单和轻量级,因为只有一个导入语句为用户提供了我的 DSL/框架所需的功能。
PS:在任何人激怒我之前 - 是的,我知道隐式转换可能带来的陷阱和肮脏。
在 Scala 中,我如何将隐式转换的导入委托给我的范围,这样我就不必拥有一个大的“环境”类,它既提供库函数/值(对于我正在创建的 DSL)也提供隐式转换?
简而言之,我可以从一个对象中移动我的隐式转换,并在我编写时仍然导入它:
导入 MyDslEnvironment._
?
这样做的目的是使我的框架的导入和使用变得简单和轻量级,因为只有一个导入语句为用户提供了我的 DSL/框架所需的功能。
PS:在任何人激怒我之前 - 是的,我知道隐式转换可能带来的陷阱和肮脏。
这可以使用特征轻松实现。只需根据需要在尽可能多的特征中定义隐式转换(以实现模块化),并将特征混合在单个对象(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
在我上面的示例中)放入特征中,而不仅仅是隐式转换(这可能需要使用自类型注释)。至此,您将基本上实现了(臭名昭著的)蛋糕模式的变体之一。见http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/Bar
Baz
我的倾向是将隐式放在一个包对象中。
假设您的工作将在包 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
通过导入 import com.acme.mydsl._,您可以获得所有包级函数定义,包括隐式转换。
我真的很喜欢包装对象。在 Java 中,仅仅为了实用功能而必须使类充满静态成员似乎总是很狡猾。包对象为这些实用程序提供了非常优雅的命名空间,包括隐式转换。