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
  }
}
War es hilfreich?

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 .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top