scala: How to get the class in its own constructor
I need access to the Class of the object being constructed in its own constructor (for various detailed reasons I don't think are relevant to my question).
I want something like this
class Foo(val i:Int)
class Bar 开发者_开发知识库extends Foo(this.getClass.getName.length)
val b = new Bar
println(b.i)
to print 3 ("Bar".length). But it doesn't. If the code above is inside some other object, "this" refers to that object. If the code above is not inside some other object (just in some package), the compiler complains with
error: this can be used only in a class, object, or template
class Bar extends Foo(this.getClass.getName)
^
CLARIFICATION: I can't change Foo to use a val in its body instead of its constructor because Foo's API already exists and is fixed (so, yes, i must be a constructor parameter). It needs an integer argument at constructor time, but that integer can only be calculated with access to the Class.
(I know the example above is still silly and degenerate. If people care, I can explain in detail why I need the class in my real project, http://code.google.com/p/factorie)
Surely, the class of the object being constructed is known to the compiler and runtime during construction. With what syntax can I get it? (Is there no such syntax? If not, I wonder why. I'm surprised it there doesn't seem to be a simple, standard way to get this.)
A lazy val solves this problem:
object Early
{
abstract class Foo { val name: String }
class Bar extends Foo { lazy val name = getClass.getName }
def
main(args: Array[String]): Unit = {
val b = new Bar
println(b.name)
}
}
Yields:
% scala Early
Early$Bar
Not sure whether this is possible in a clean way. If you like hacks you could do
class Bar extends Foo((new Exception).getStackTrace.apply(0).getClassName)
However I strongly advertise against it!
This appears to satisfy your requirement without using a lazy val and without altering the base class:
scala> class Base(val name: String)
defined class Base
scala> class Derived extends Base(classOf[Derived].getName)
defined class Derived
scala> new Derived name
res0: String = Derived
You are going to have to explain your motivation for wanting to do this. Does name have to be a constructor parameter of Foo
or can it be an abstract member? Does it have to be a val
or will a def
do.
You can do this
class Foo(val name: String)
class Bar extends Foo("") {
override val name = getClass.getName
}
and new Bar().name
will give Bar
But I suspect that if your true motivation is known then there is a better way to do what you really want.
How about
class Bar extends Foo(classOf[Bar].getName.length)
What about this:
class Foo(otherName: Option[String] = None) {
val name = otherName.getOrElse(this.getClass.getName)
}
class Bar extends Foo()
val b = new Bar
println(b.name)
精彩评论