不能调用new a trait时定义的apply函数

时间:2014-06-14 10:30:48

标签: scala

object test {
  trait Test {
    def apply() = {
      println("calling apply in trait test")
      this
    }
  }
  object Test {
    def apply(f: Int => String): Test = {
      println("calling apply in object Test")
      new Test {
        println("test123")
        def apply(a: Int) = f(a)  // this apply function should be available when call Test(f)?
      }
    }
  }
  def fun(a:Int)=a.toString
  val f=fun _
  val a=Test(f)
  a()
  a(1) // why this failed? a is created by calling Test(f) which is actually 
       //calling apply function of object Test, and that function return a Test
       //with an addition function of apply(a:Int). And a(1) is actually calling 
       //apply(1), but why it doesn't compile? 
}

2 个答案:

答案 0 :(得分:4)

您的签名:

def apply(f: Int => String): Test = { … }

将结果限制为Test特征,但不包括新的apply。通过省略结果类型,返回的对象将是Test+apply,它将按照您的预期执行:

def apply(f: Int => String) = { … }

答案 1 :(得分:2)

此失败的原因是您的类型Test是使用apply方法定义的,该方法采用空参数列表。使用new Test { ... },您可以创建Test的匿名子类。虽然您使用另一个带有apply参数的版本重载Int,但对象的apply方法的返回类型仅为Test。因此,从外部来看,这种重载方法是不可见的。

说明您的问题:

trait Foo

def mkFoo(): Foo = new Foo { def bar = 1234 }

val f = mkFoo()
f.bar  // we don't know anything about bar

只需定义特征Test即可包含其他apply方法:

trait Test {
  def apply() = {
    println("calling apply in trait test")
    this
  }

  def apply(i: Int): String  // abstract
}

编辑:作为完整性问题,如果您使用@samuel tardieu答案中所示的“精炼”返回类型,从技术上讲,您使用的是“结构类型”,它带有一点点性能阴谋,因为该方法将使用运行时反射调用。