2012-09-01 5 views
24

Comment passer un argument de la meilleure façon?Comment passer un argument de tuple de la meilleure façon?

Exemple:

def foo(...): (Int, Int) = ... 

def bar(a: Int, b: Int) = ... 

Maintenant, je voudrais passer la sortie de foo-bar. Ceci peut être réalisé avec:

val fooResult = foo(...) 
bar(fooResult._1, fooResult._2) 

Cette approche ressemble un peu laid, surtout quand nous traitons avec un n uplet avec n > 2. Nous devons également stocker le résultat de foo dans une valeur supplémentaire, car sinon, foo doit être exécuté plusieurs fois en utilisant bar(foo._1, foo._2).

Existe-t-il un meilleur moyen de passer le tuple en argument?

+1

duplication possible de [Comment appliquer une fonction à un tuple?] (Http://stackoverflow.com/questions/1987820/how-to-apply-a-function-to-a-tuple) –

Répondre

39

Il existe une méthode tupled spéciale disponible pour toutes les fonctions:

val bar2 = (bar _).tupled // or Function.tupled(bar _) 

bar2 prend un tuple de (Int, Int) (même que bar arguments). Maintenant, vous pouvez dire:

bar2(foo()) 

Si vos méthodes étaient en fait des fonctions (notez le mot-clé val) la syntaxe est beaucoup plus agréable:

val bar = (a: Int, b: Int) => //... 
bar.tupled(foo()) 

Voir aussi

+0

Merci, C'est ce que je cherchais. Cela fera l'affaire pour moi. Question supplémentaire: Vous avez mentionné qu'il y a une différence entre une méthode et une fonction - quelle est la différence? J'aimerais en savoir plus à ce sujet. Pouvez-vous me donner quelques références/liens où je peux lire plus à ce sujet? –

+3

@JohnThreepwood: les méthodes de Scala traduisent en méthodes Java. Les fonctions de Scala se traduisent par des objets. Dans Scala, ceci est principalement transparent (recherche de "* eta-expansion *"), mais parfois la syntaxe est légèrement différente. [Cet article] (http://jim-mcbeath.blogspot.no/2009/05/scala-functions-vs-methods.html) est très complet. –

+0

Super, merci beaucoup. –

8

En utilisant tupled, as @Tomasz mentionne, est une bonne approche.

Vous pouvez également extraire le tuple retourné par foo lors de l'affectation:

val (x, y) = foo(5) 
bar(x, y) 

Ceci a l'avantage de code plus propre (pas _1 et _2), et vous permet d'attribuer des noms descriptifs pour x et y, ce qui rend votre code plus facile à lire.

+0

Merci. Je suis d'accord, c'est plus lisible. Je vais garder ce truc en tête. Mais la valeur supplémentaire m'ennuie un peu. Je voudrais passer à travers sans enregistrer le résultat à une valeur supplémentaire. Mais encore merci pour cet indice! –

5

Il faut savoir aussi sur

foo(...) match { case (a,b) => bar(a,b) } 

comme une alternative qui ne explicitement créer vous pas besoin d'un fooResult temporaire. C'est un bon compromis quand la vitesse et le manque d'encombrement sont importants. Vous pouvez créer une fonction avec bar _, puis la convertir pour prendre un seul argument de ligne avec .tupled, mais cela crée deux nouveaux objets de fonction chaque fois que vous appelez la paire; vous pourriez stocker le résultat, mais cela pourrait encombrer votre code inutilement.

Pour une utilisation quotidienne (à savoir ce n'est pas la partie limitant la performance de votre code), vous pouvez juste

(bar _).tupled(foo(...)) 

en ligne.Bien sûr, vous créez deux objets de fonction supplémentaires, mais vous avez probablement juste créé le tuple aussi, donc vous ne vous souciez pas que beaucoup, non?

+0

Merci d'avoir signalé cette alternative. Mais pourquoi un tuple comme valeur de retour est-il un signe de ne pas se soucier de la performance? Mais oui, vous avez raison, dans mon programme, la performance n'a pas beaucoup d'importance. –

+0

@JohnThreepwood - Vous devez créer un objet pour renvoyer un tuple. Si ce que vous faites est cher par rapport à la création d'objet, alors il est probablement aussi cher comparé à deux créations d'objet (ce qui est ce que vous obtenez avec 'bar _' et' .tupled'). Si ce que vous faites est bon marché par rapport à la création d'objet, pourquoi avez-vous créé un objet? Vous devriez avoir passé un objet avec des vars que vous pourriez définir. (Cette dernière approche est quelque chose que vous devriez faire rarement, voire pas du tout - la création d'objet est assez bon marché.) –

+0

Merci pour la clearification. L'explication a du sens, je vais le garder à l'esprit. –

Questions connexes