Scala - trait 成员初始化:使用 traits 修改 class 成员
Scala - trait member initialization: use traits to modify class member
可能标题不是很清楚。这是我的问题。
假设我有一个使用一系列配置参数定义应用程序的特征。这些参数包含在一个Map
中,其中一些有默认值。
trait ConfApp {
val dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
所以我可以创建一个自定义应用程序如下:
class MyApp extends ConfApp {
override val dbName = "my_app_db"
// print app configuration parameters
println(conf)
def add() = {...}
...
}
val M1 = new Myapp // Map(db -> my_app_db, foo -> bar)
我想创建其他特征来设置一些其他配置参数。换句话说,我希望能够做类似的事情:
class MyApp2 extends ConfApp with LogEnabled {
override val dbName = "my_app2_db"
// print app configuration parameters
println(conf)
def add() = {...}
...
}
val M2 = new Myapp2 // Map(db -> my_app_db, foo -> bar, log -> true)
到目前为止,我已经设法做到了以下几点:
trait LogEnabled {
val conf: scala.collection.mutable.Map[String, Any]
conf("log") = true
}
trait LogDisabled {
val conf: scala.collection.mutable.Map[String, Any]
conf("log") = false
}
trait ConfApp {
val dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
class MyApp extends ConfApp {
val dbName = "my_app_db"
println(conf)
}
class MyApp2 extends ConfApp with LogDisabled {
val dbName = "my_app_db"
println(conf)
}
val M = new MyApp // Map(db -> my_app_db, foo -> bar)
val M2 = new MyApp2 // Map(log -> false, foo -> bar, db -> null)
但是正如您在 M2
中看到的那样,db
参数是 null
。我不明白我做错了什么。
真诚地,我一点也不喜欢这种使用可变 Map 的方法,但我没能做得更好。
如果我是你,我不会为此使用 vals,因为初始化顺序存在很多问题。一方面,您还可以在特征中使用自引用来指定它们必须与 ConfApp
混合在一起。那就是说我会做这样的事情:
trait LogEnabled { self: ConfApp =>
self.conf("log") = true
}
trait LogDisabled { self: ConfApp =>
self.conf("log") = false
}
trait ConfApp {
def dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
class MyApp extends ConfApp {
override def dbName = "my_app_db"
println(conf)
}
class MyApp2 extends ConfApp with LogDisabled {
override def dbName = "my_app_db"
println(conf)
}
这似乎工作正常。
您仍然可以这样使用不可变 Map
:
scala> trait ConfApp {
| val dbName: String
| def conf: Map[String, Any] = Map("db" -> dbName, "foo" -> "bar")
| }
defined trait ConfApp
scala> trait LogEnabled extends ConfApp {
| override def conf = super.conf.updated("log", true)
| }
defined trait LogEnabled
scala> trait LogDisabled extends ConfApp {
| override def conf = super.conf.updated("log", false)
| }
defined trait LogDisabled
scala> class MyApp extends ConfApp {
| val dbName = "my_app_db"
| println(conf)
| }
defined class MyApp
scala> class MyApp2 extends ConfApp with LogDisabled {
| val dbName = "my_app_db2"
| println(conf)
| }
defined class MyApp2
scala> new MyApp
Map(db -> my_app_db, foo -> bar)
res0: MyApp = MyApp@ccc268e
scala> new MyApp2
Map(db -> my_app_db2, foo -> bar, log -> false)
res1: MyApp2 = MyApp2@59d91aca
scala> new ConfApp with LogDisabled with LogEnabled {
| val dbName = "test1"
| println(conf)
| }
Map(db -> test1, foo -> bar, log -> true)
res2: ConfApp with LogDisabled with LogEnabled = $anon@16dfdeda
scala> new ConfApp with LogEnabled with LogDisabled {
| val dbName = "test2"
| println(conf)
| }
Map(db -> test2, foo -> bar, log -> false)
res3: ConfApp with LogEnabled with LogDisabled = $anon@420c2f4a
如果您需要 val conf
而不是 def conf
,您可以这样做:
scala> class MyApp extends ConfApp {
| val dbName = "my_app_db"
| override val conf = super.conf
| println(conf)
| }
defined class MyApp
scala> new MyApp
Map(db -> my_app_db, foo -> bar)
res4: MyApp = MyApp@17ebbd2a
可能标题不是很清楚。这是我的问题。
假设我有一个使用一系列配置参数定义应用程序的特征。这些参数包含在一个Map
中,其中一些有默认值。
trait ConfApp {
val dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
所以我可以创建一个自定义应用程序如下:
class MyApp extends ConfApp {
override val dbName = "my_app_db"
// print app configuration parameters
println(conf)
def add() = {...}
...
}
val M1 = new Myapp // Map(db -> my_app_db, foo -> bar)
我想创建其他特征来设置一些其他配置参数。换句话说,我希望能够做类似的事情:
class MyApp2 extends ConfApp with LogEnabled {
override val dbName = "my_app2_db"
// print app configuration parameters
println(conf)
def add() = {...}
...
}
val M2 = new Myapp2 // Map(db -> my_app_db, foo -> bar, log -> true)
到目前为止,我已经设法做到了以下几点:
trait LogEnabled {
val conf: scala.collection.mutable.Map[String, Any]
conf("log") = true
}
trait LogDisabled {
val conf: scala.collection.mutable.Map[String, Any]
conf("log") = false
}
trait ConfApp {
val dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
class MyApp extends ConfApp {
val dbName = "my_app_db"
println(conf)
}
class MyApp2 extends ConfApp with LogDisabled {
val dbName = "my_app_db"
println(conf)
}
val M = new MyApp // Map(db -> my_app_db, foo -> bar)
val M2 = new MyApp2 // Map(log -> false, foo -> bar, db -> null)
但是正如您在 M2
中看到的那样,db
参数是 null
。我不明白我做错了什么。
真诚地,我一点也不喜欢这种使用可变 Map 的方法,但我没能做得更好。
如果我是你,我不会为此使用 vals,因为初始化顺序存在很多问题。一方面,您还可以在特征中使用自引用来指定它们必须与 ConfApp
混合在一起。那就是说我会做这样的事情:
trait LogEnabled { self: ConfApp =>
self.conf("log") = true
}
trait LogDisabled { self: ConfApp =>
self.conf("log") = false
}
trait ConfApp {
def dbName: String
lazy val conf: scala.collection.mutable.Map[String, Any] = scala.collection.mutable.Map("db" -> dbName, "foo" -> "bar")
}
class MyApp extends ConfApp {
override def dbName = "my_app_db"
println(conf)
}
class MyApp2 extends ConfApp with LogDisabled {
override def dbName = "my_app_db"
println(conf)
}
这似乎工作正常。
您仍然可以这样使用不可变 Map
:
scala> trait ConfApp {
| val dbName: String
| def conf: Map[String, Any] = Map("db" -> dbName, "foo" -> "bar")
| }
defined trait ConfApp
scala> trait LogEnabled extends ConfApp {
| override def conf = super.conf.updated("log", true)
| }
defined trait LogEnabled
scala> trait LogDisabled extends ConfApp {
| override def conf = super.conf.updated("log", false)
| }
defined trait LogDisabled
scala> class MyApp extends ConfApp {
| val dbName = "my_app_db"
| println(conf)
| }
defined class MyApp
scala> class MyApp2 extends ConfApp with LogDisabled {
| val dbName = "my_app_db2"
| println(conf)
| }
defined class MyApp2
scala> new MyApp
Map(db -> my_app_db, foo -> bar)
res0: MyApp = MyApp@ccc268e
scala> new MyApp2
Map(db -> my_app_db2, foo -> bar, log -> false)
res1: MyApp2 = MyApp2@59d91aca
scala> new ConfApp with LogDisabled with LogEnabled {
| val dbName = "test1"
| println(conf)
| }
Map(db -> test1, foo -> bar, log -> true)
res2: ConfApp with LogDisabled with LogEnabled = $anon@16dfdeda
scala> new ConfApp with LogEnabled with LogDisabled {
| val dbName = "test2"
| println(conf)
| }
Map(db -> test2, foo -> bar, log -> false)
res3: ConfApp with LogEnabled with LogDisabled = $anon@420c2f4a
如果您需要 val conf
而不是 def conf
,您可以这样做:
scala> class MyApp extends ConfApp {
| val dbName = "my_app_db"
| override val conf = super.conf
| println(conf)
| }
defined class MyApp
scala> new MyApp
Map(db -> my_app_db, foo -> bar)
res4: MyApp = MyApp@17ebbd2a