2010-10-28 4 views
3

OK la question pourrait ne pas dire beaucoup, mais voici l'affaire: J'apprends la scala et ai décidé de faire une classe d'utilité "FuncThread" avec une méthode qui reçoit un by- fonction des paramètres de nom (je suppose que son appelé parce que c'est une fonction mais sans une liste de paramètres), puis démarre un thread avec un runable qui à son tour exécute la fonction passée, je l'ai écrit une telle classe comme suit:pourquoi ce paramètre scala by-name se comportent étrangement

class FuncThread 
{ 
    def runInThread(func: => Unit) 
    { 
    val thread = new Thread(new Runnable() 
    { 
     def run() 
     { 
      func 
     } 
    } 

    thread.start() 
    } 
} 

Ensuite, j'ai écrit un test de junit comme suit:

@Test 
def weirdBehaivorTest() 
{ 
    var executed = false 
    val util = new FuncThread() 
    util.runInThread 
    { 
    executed = true 
    } 

    //the next line makes the test pass.... 
    //val nonSense :() => Unit =() => { Console println "???" } 

    assertTrue(executed) 
} 

Si je décommente la deuxième ligne commentée, le test réussit mais s'il reste commenté, le test échoue, est-ce le bon comportement? comment et quand les fonctions de paramètres by-name sont-elles exécutées?

Je sais que Scala a la bibliothèque d'acteurs, mais je voulais essayer depuis que je l'ai toujours voulu faire en Java

Répondre

7

Est-ce juste une condition de course? runInThread démarre le thread mais vos tests d'assertion sont 'exécutés' avant que l'autre thread ne le mette à true. L'ajout de votre ligne supplémentaire signifie que plus de code (et donc le temps) est exécuté avant le test, ce qui rend plus vraisemblable que 'exécuté' a été mis à

+0

wow c'était ça, une condition de course, vient d'ajouter un sommeil (10) et ça l'a corrigé! – Harima555

+6

Non, vous avez ajouté un sleep (10) et cela masquait l'erreur, sans la réparer. –

+0

oui vous avez raison, je devrais utiliser wait/notify à la place, mais je voulais juste lancer un test rapide pour jouer avec scala =) – Harima555

4

Notez que (à partir de Scala 2.8), vous construisez essayaient d'écrire est disponible dans la bibliothèque standard

import scala.actors.Futures._ 

future{ 
    executed = true 
} 

Cette construction est en fait plus puissant que ce que vous décrivez, le calcul du fil peut retourner une valeur, et qui peut être attendu.

import scala.actors.Futures._ 

//forks off expensive calculation 
val expensiveToCalculateNumber:Future[Int] = future{ 
    bigExpensiveCalculation() 
} 

// do a lot of other stuff 

//print out the result of the expensive calculation if it's ready, otherwise wait until it is 
println(expensiveToCalculateNumber()); 
+0

si gentil! merci de m'avoir signalé, je n'ai pas regardé le paquet de l'acteur, mais plus je découvre scala, plus j'en tombe amoureux =) – Harima555