开发者

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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜