【问题标题】:How to make the type checking at compile time?如何在编译时进行类型检查?
【发布时间】:2011-05-23 05:01:24
【问题描述】:

TraversableOnce 中,有一个sum 方法只有在包含的类型为Numeric 时才可用(否则它不会编译)。我想知道这是否可用于其他情况(以避免运行时检查)。

特别是我们有两个特征 A 和 B 的情况。我们希望有一个方法 f 只能在对象继承 both A 和 B 时使用。但如果它不是仅扩展其中之一。我不想再写一个trait AB extends A with B。如果不是两个特征都被继承,我只想无法使用f

package com.example

trait Base
trait Foo extends Base {
  def g = println("foo bar " + toString)
}
trait Bar extends Base {
  /* If this is both Foo and Bar, I can do more */
  def f = {
    if (!this.isInstanceOf[Foo]) error("this is not an instance of Foo")
    this.asInstanceOf[Foo].g
  }
}
object Test {
  def main(args: Array[String]): Unit = {
    object ab extends Foo with Bar
    object ba extends Bar with Foo
    object b extends Bar
    ab.f
    ba.f
    // I don't want next line to compile:
    try { b.f } catch { case e: RuntimeException => println(e) }
  }
}

编辑:解决方案,感谢@Aaron Novstrup

trait Bar extends Base { self =>
  def f(implicit ev: self.type <:< Foo) = {
    //self.asInstanceOf[Foo].g // [1]
    ev(this).g // [2]
  }
}

现在在main 中,b.f 无法编译。不错

编辑 2:将第 [1] 行更改为 [2] 反映了@Aaron Novstrup 对答案的更改

编辑 3:不使用 self 反映 @Aaron Novstrup 回答的变化

trait Bar extends Base {
  /* If this is both Foo and Bar, I can do more */
  def f(implicit ev: this.type <:< Foo) = {
    ev(this).g
  }
}

【问题讨论】:

  • 您也可以使用ev 参数来避免强制转换——它是Function1[self.type, Foo]。更新了我的答案以进行演示。

标签: scala types traits


【解决方案1】:

是的,您可以:

trait A {
   def bar = println("I'm an A!")
}

trait B { 
   def foo(implicit ev: this.type <:< A) = { 
      ev(this).bar
      println("and a B!")
   }
}

如果对象的静态类型(在调用站点)扩展A,编译器将只能提供evidence 参数。

【讨论】:

  • 很好,它正在工作,谢谢。我第一次看到 self 不是用来强制继承链,而是建议改进。因此,我第一次离不开。
  • 其实self类型是不需要的。你可以使用this
  • @pedrofurla 不。 ev 的类型为 &lt;:&lt;[this.type, A],它扩展了 Function1[this.type, A]
  • 其实这次{self =&gt; 也有不同的做法
  • 我从未意识到 <: function1>
【解决方案2】:

知道sum的签名是

def sum [B >: A] (implicit num: Numeric[B]) : B

您似乎假设数字类型扩展了Numeric,这不是真的。实际上它们被隐式转换为 Numeric,在 Int 的情况下,使用的隐式是 scala.math.Numeric.IntIsIntegral,它定义了像 加和

所以对ATraversableOnce[A].sum的类型的限制是通过隐式提供所需操作的存在来实现的。

这只是对 Numeric 和类型类的整体工作原理的简要说明。有关更多信息,请查看 math.Numeric.XisY、math.Integral 和 math.Fractional 的来源以及类型类的工作原理:implicit-tricks-type-class-patterntype-class-pattern-example

【讨论】:

  • 这不是完全正确,但很接近。没有从IntNumeric[Int] 的隐式转换,但在作用域内有一个隐式Numeric[Int] 对象(即IntIsIntegral)允许编译器将隐式参数提供给sum 方法。跨度>
猜你喜欢
  • 2012-06-10
  • 2018-11-05
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多