【问题标题】:scala: How to get the class in its own constructorscala:如何在自己的构造函数中获取类
【发布时间】:2011-04-17 21:17:34
【问题描述】:

我需要访问在其自己的构造函数中构造的对象的类(出于各种我认为与我的问题无关的详细原因)。

我想要这样的东西

class Foo(val i:Int)
class Bar extends Foo(this.getClass.getName.length)
val b = new Bar
println(b.i)

打印3(“栏”.Length)。但事实并非如此。如果上面的代码在某个其他对象中,“this”指的是那个对象。如果上面的代码不在某个其他对象中(只是在某个包中),编译器会报错

error: this can be used only in a class, object, or template
class Bar extends Foo(this.getClass.getName)
                      ^

澄清:我不能将 Foo 更改为在其主体中使用 val 而不是其构造函数,因为 Foo 的 API 已经存在并且是固定的(所以,是的,i 必须是构造函数参数)。它在构造函数时需要一个整数参数,但该整数只能通过访问类来计算。

(我知道上面的例子还是很傻很堕落。如果有人关心,我可以详细解释一下为什么我在实际项目中需要这个类,http://code.google.com/p/factorie

在构造过程中,编译器和运行时肯定知道正在构造的对象的类。我可以获得什么语法吗? (没有这样的语法吗?如果没有,我想知道为什么。我很惊讶似乎没有一种简单、标准的方法来获得它。)

【问题讨论】:

  • 这是我在 StackOverflow 上发布的第一个问题。如此迅速地得到答案真是令人难以置信。谢谢你们。然而,我现在看到,我必须使我的示例更复杂,以更好地反映我的真实用例。我认为现在要做的是编辑我的问题。我现在要这样做。 span>
  • 您是否意识到对公共val 的访问仍由(常规多态)方法介导?
  • @chrispy:感谢您的建议,但 Geoff Reedy 的回答对原始问题和稍微编辑的问题都有效。他的答案现在被接受了。 span>

标签: scala constructor


【解决方案1】:

懒惰的 val 解决了这个问题:

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

产量:

% scala Early
Early$Bar

【讨论】:

  • 顺便说一下,Early 这个名字是我第一次尝试使用“早期定义”结构解决这个问题时留下的。
  • 兰德尔,谢谢您的回答。不幸的是,它对我没有用,正如我编辑的问题中现在更好地描述的那样。
【解决方案2】:

不确定这是否可能以干净的方式进行。如果你喜欢黑客,你可以做

class Bar extends Foo((new Exception).getStackTrace.apply(0).getClassName)

但是我强烈宣传反对它!

【讨论】:

    【解决方案3】:

    这似乎满足了您的要求,无需使用惰性 val 且无需更改基类:

    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
    

    【讨论】:

      【解决方案4】:

      你将不得不解释你想要这样做的动机。 name 必须是Foo 的构造函数参数还是可以是抽象成员?它必须是val 还是def

      你可以这样做

      class Foo(val name: String)
      class Bar extends Foo("") {
        override val name = getClass.getName
      }
      

      new Bar().name 会给酒吧

      但我怀疑,如果知道你的真正动机,那么就有更好的方法来做你真正想做的事。

      【讨论】:

      • 杰夫,谢谢。这可以解决问题。它保留了 Foo 的原始 API,同时允许使用 this.getClass 初始化 val。我想 Bar 和 Foo 占用相同数量的内存,但我不确定,也不知道如何验证这一点。
      • @mccallum 您可以使用javap -p classname 显示类中的字段。在这种情况下,Foo 和 Bar 中的值都会有一个字段,因此会有额外的存储空间。如果 Foo 的构造函数参数是一个对象,最好使用 null 作为参数来最小化存储需求。
      【解决方案5】:

      怎么样

      类 Bar 扩展 Foo(classOf[Bar].getName.length)

      【讨论】:

        【解决方案6】:

        这个呢:

          class Foo(otherName: Option[String] = None) {
            val name = otherName.getOrElse(this.getClass.getName)
          }
          class Bar extends Foo()
          val b = new Bar
          println(b.name)
        

        【讨论】:

          猜你喜欢
          • 2018-10-19
          • 1970-01-01
          • 2013-01-11
          • 1970-01-01
          • 2012-01-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多