Frage

Ich habe scala lernen, und ich muss sagen, dass es eine wirklich coole Sprache ist. Besonders gut gefällt mir seine Pattern-Matching-Funktionen und Funktionsliteralen aber ich komme aus einer Javascript, Rubin Hintergrund und einer meiner Lieblings-Muster in diesen Sprachen ist die faul Funktion und Methodendefinition Muster. Ein Beispiel in Javascript ist

var foo = function() {
  var t = new Date();
  foo = function() {
    return t;
  };
  return foo();
};

Der gleiche Code mit kleineren Verbesserungen arbeitet in Rubin, wo man nur das Singleton-Objekt verwenden Sie die Methode neu zu definieren, nachdem die Berechnung durchgeführt wird. Diese Art der Sache kommt in wirklich praktisch, wenn teure Berechnung beteiligt ist, und Sie müssen nicht im Voraus wissen, wenn Sie das Ergebnis gehen zu müssen. Ich weiß, dass in scala ich einen Cache verwenden kann, die gleiche Art von Ergebnis zu simulieren, aber ich versuche bedingte Kontrollen zu vermeiden und so weit meine Experimente haben negative Ergebnisse zurückgegeben. Hat jemand wissen, ob es ein fauler Funktion oder Methode Definitionsmuster in scala ist?

Hinweis: Der Javascript-Code ist von Peter Michaux Website <. / p>

War es hilfreich?

Lösung

Alles, was Code in JavaScript kompliziert erscheint nur versuchen, den Wert des Datums cachen. In Scala, können Sie das gleiche erreichen trivialer:

lazy val foo = new Date

Und wenn Sie wollen nicht einmal eine val machen, sondern wollen eine Funktion aufzurufen, die nur den teuren Code ausführen, wenn sie sie braucht, können Sie

def maybeExpensive(doIt: Boolean, expensive: => String) {
  if (doIt) println(expensive)
}
maybeExpensive(false, (0 to 1000000).toString)  // (0 to 1000000).toString is never called!
maybeExpensive(true, (0 to 10).toString)        // It is called and used this time

, wo das Muster expensive: => String einen Neben Namen Parameter aufgerufen wird, die man sich vorstellen kann, wie: „Gib mir etwas, das einen String auf Anfrage generieren.“ Beachten Sie, dass, wenn Sie es zweimal verwenden, wird es jedes Mal regenerieren, das ist, wo Randall Schultz‘handliche Muster kommt in:

def maybeExpensiveTwice(doIt: Boolean, expensive: => String) {
  lazy val e = expensive
  if (doIt) {
    println(e)
    println("Wow, that was " + e.length + " characters long!")
  }
}

Jetzt erzeugen Sie nur, wenn Sie es brauchen (über die by-name-Parameter) und lagert und wiederverwenden es, wenn Sie es wieder benötigen (über die faule val).

es also tun, um diese Art und Weise, nicht die JavaScript-Art und Weise, auch wenn Sie könnte machen Scala viel wie der JavaScript aussehen.

Andere Tipps

Scala hat lazy vals, deren initializers werden nicht ausgewertet, sofern und solange das val verwendet wird. Lazy vals als Methode lokale Variablen verwendet werden können.

Scala hat auch nach Namen Parameter Methode, deren tatsächlichen Parameter Ausdrücke werden in einem Thunk gewickelt und dass thunk jedes Mal ausgewertet wird der formale Parameter in der Methode Körper verwiesen wird.

Zusammen stellen diese verwendet werden können lazy evaluation Semantik wie sind die Standards in Haskell (zumindest in meinem sehr begrenzten Verständnis von Haskell) zu erreichen.

def meth(i: => Int): Something = {
  //        ^^^^^^ by-name parameter syntax
  lazy val ii = i
  // Rest of method uses ii, not i
}

Bei diesem Verfahren wird der Ausdruck als eigentlicher Parameter verwendet werden ausgewertet entweder Null mal (wenn der dynamische Ausführungspfad des Verfahrens Körper nie ii verwendet) oder einmal (wenn es ii ein oder mehrere Male verwendet).

Sie können eine faule val definieren, die eine Funktion ist:

lazy val foo = {
  val d = new Date
  () => { d }
}

println(foo())

foo() wird nun die selber als Date-Objekt jedes Mal, Objekt, das das erste Mal foo aufgerufen werden initialisiert wird.

den Code ein wenig zu erklären, das erste Mal, foo () aufgerufen { val d = new Date; () => { d } } ausgeführt wird, d auf ein neues Datum Wert zugewiesen wird dann bewerten sie den letzten Ausdruck () => { d } und weisen Sie auf die foo Wert. Dann foo ist eine Funktion ohne Parameter, die Rückkehr d.

Ich denke, einige der Responder ein wenig durch die Art und Weise Sie die Frage formuliert verwirrt waren. Das Scala-Konstrukt Sie hier wollen, ist eine einfache faul Definition:

lazy val foo = new java.util.Date

Der Aufbau des Date-Objekt höchstens einmal auftreten und bis zum ersten Verweis auf foo verschoben werden.

ich nichts gewusst zu Ruby, aber scala hat Singleton-Objekt Muster auch:

Welcome to Scala version 2.8.0.r22634-b20100728020027 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object LazyInit {                                       
     |     val msec = { println("Hi,I'm here!");   System.currentTimeMillis }
     | }
defined module LazyInit

scala> System.currentTimeMillis                                              
res0: Long = 1282728315918

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)              
Hi,I'm here!
1282728319929 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728322936 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728324490 : 1282728319930

scala> 

Wenn Sie Funktion erhalten möchten, können Sie es von einem Funktionstyp machen Subtyp:

scala> object LazyFun extends (() => Long) {            
     |     val msec = System.currentTimeMillis          
     |     def apply() = msec                           
     | }
defined module LazyFun

scala> System.currentTimeMillis                         
res2: Long = 1282729169918

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729190384 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729192972 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729195346 : 1282729190384

Ich denke, was Sie meinen „lazy-Funktion“ ist Funktionsliteral oder anonyme Funktion.

In Scala Sie Dinge wie dies tun könnte, sehr ähnlich wie die Javascript-Code Sie auf dem Laufenden.

val foo = () => {
    val t = new Date()
    val foo = () => {t}

    foo()
}

println ("Hello World:" + foo())

Der Hauptunterschied besteht darin, dass:

  • Sie konnte nicht Neuzuordnung der äußere foo
  • Es gibt keine "Funktion" Keyword, stattdessen verwenden Sie so etwas wie (s: String) => {code}
  • Die letzte Aussage ist der Rückgabewert eines Blocks, so dass Sie nicht brauchen, „return“ hinzufügen.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top