Obtenez des arguments de retour de la fonction partiellement appliquée dans scala
-
26-10-2019 - |
Question
Y at-il une façon scala pour obtenir les arguments de retour d'une fonction appliquée déjà en partie?
Est-ce même du sens, devrait être fait, ou se insère dans tous les cas d'utilisation?
exemple:
def doStuff(lower:Int,upper:Int,b:String)=
for(turn <- lower to upper) println(turn +": "+b)
Imaginez qu'à un moment donné, je sais que l'argument « inférieur » et je reçois une fonction de l'appliquer à « doStuff »
val lowerDoStuff = doStuff(3,_:Int,_:String)
est-il pour moi un moyen d'obtenir que 3 de retour? (Par souci d'exemple, imaginez que je suis dans une fonction qui n'a reçu « lowerDoStuff » et doit maintenant connaître le premier argument)
Idiomatic Scala est préféré à l'introspection / réflexion (si possible).
La solution
idiomatiques Scala: non, vous ne pouvez pas. Vous avez dit spécifiquement que le premier argument n'est plus pertinent. Si le compilateur peut faire disparaître tout à fait, qui est le mieux: vous dites que vous avez une fonction qui dépend d'un int et une chaîne, et vous n'avez pas fait des promesses au sujet de ce qui a généré. Si vous vraiment besoin de cette valeur, mais vous avez vraiment besoin de passer une fonction 2 argument, vous pouvez le faire à la main:
class Function2From3[A,B,C,Z](f: (A,B,C) => Z, val _1: A) extends Function2[B,C,Z] {
def apply(b: B, c: C) = f(_1, b, c)
}
val lowerDoStuff = new Function2From3(doStuff _, 3)
Maintenant, quand vous obtenez la fonction plus tard, vous pouvez match de modèle pour voir si elle est un Function2From3, puis lisez la valeur:
val f: Function2[Int,String,Unit] = lowerDoStuff
f match {
case g: Function2From3[_,_,_,_] => println("I know there's a "+g._1+" in there!")
case _ => println("It's all Greek to me.")
}
(s'il est important pour vous que ce soit un entier, vous pouvez supprimer A
comme paramètre générique et faire _1
être un entier - et peut-être juste l'appeler lower
pendant que vous y êtes).
Réflexion: non, vous ne pouvez pas (pas en général). Le compilateur est plus intelligent que ça. Le bytecode généré (si nous emballons votre code class FuncApp
) est:
public final void apply(int, java.lang.String);
Signature: (ILjava/lang/String;)V
Code:
0: aload_0
1: getfield #18; //Field $outer:LFuncApp;
4: iconst_3
5: iload_1
6: aload_2
7: invokevirtual #24; //Method FuncApp.doStuff:(IILjava/lang/String;)V
10: return
Notez que le iconst_3
? C'est là votre 3 est allé - il a disparu dans le bytecode. Il n'y a même pas un champ privé caché contenant la valeur plus.