Wie die Typprüfung bei der Kompilierung machen?
Frage
TraversableOnce
, gibt es eine sum
Methode, die nur verwendbar ist, wenn der darin enthaltenen Typ ist Numeric
(sonst wird es nicht kompilieren). Ich frage mich, ob dies für anderen Fall verwendbar ist (zur Vermeidung von Laufzeitüberprüfung).
Insbesondere der Fall, wo wir zwei Züge A und B haben Wir wollen eine Methode f
haben, die nur verwendet werden, wenn sich das Objekt erbt beide A und B. Aber nicht, wenn es sich nur einer von ihnen. Ich will nicht eine andere trait AB extends A with B
machen. Ich will nur nicht in der Lage sein f
zu verwenden, wenn nicht beiden Züge vererbt werden.
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) }
}
}
EDIT: Lösung, dank @Aaron Novstrup
trait Bar extends Base { self =>
def f(implicit ev: self.type <:< Foo) = {
//self.asInstanceOf[Foo].g // [1]
ev(this).g // [2]
}
}
Jetzt in main
, b.f
nicht kompiliert. Nizza
EDIT 2: geänderte Zeile [1] bis [2] spiegeln Änderungen in der Antwort von @Aaron Novstrup
EDIT 3: ohne self
mit den Änderungen in der Antwort von @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
}
}
Lösung
Ja, Sie können:
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!")
}
}
Der Compiler wird nur in der Lage sein, die evidence
Parameter zu liefern, wenn das statische Typ des Objekts (an der Aufrufstelle) erstreckt A
.
Andere Tipps
Zu wissen, dass die Signatur der Summe
def sum [B >: A] (implicit num: Numeric[B]) : B
Sie scheinen, dass Nummerntypen werden unter der Annahme erstreckt Numeric , das ist nicht wahr. Eigentlich sind sie implizit konvertiert Numeric , im Falle von Int die implizite gebrauchte ist scala.math.Numeric.IntIsIntegral , die Operationen wie definieren < em> und und mal .
So die Beschränkung auf, welche Arten von A a TraversableOnce [A] .sum erlaubt wird durch die Existenz von impliziten Schwärzler Hotels bieten die erforderlichen Operationen erreicht wird.
Das ist nur eine kurze Erläuterung der Gesamtarbeitsweise Numerische und Typklassen. Weitere überprüfen Sie die Quellen von math.Numeric.XisY, math.Integral und math.Fractional und wie Typklassen Werke: implizite-Tricks-Typ-Klasse-Muster und type-Klasse-Muster-Beispiel .