1

すでに部分的に適用されている関数から引数を取り戻す方法はscalaにありますか?

これは意味がありますか、実行する必要がありますか、または任意のユースケースに適合しますか?

例:

def doStuff(lower:Int,upper:Int,b:String)= for(turn <- lower to upper) println(turn +": "+b)

ある時点で「lower」引数を知っていて、それを「doStuff」に適用する関数を取得したと想像してください。

val lowerDoStuff = doStuff(3,_:Int,_:String)

その3を取り戻す方法はありますか?(例として、「lowerDoStuff」のみを受け取った関数の中にいて、最初の引数を知る必要があると想像してください)

慣用的なscalaは、内省/反省よりも好まれます(可能な場合)。

4

1 に答える 1

7

慣用的なScala:いいえ、できません。あなたは、最初の議論はもはや関係がないと具体的に言っています。コンパイラーがそれを完全に消滅させることができるのであれば、それが最善です。つまり、intと文字列に依存する関数があり、それを生成したものについては何も約束していません。その値が本当に必要であるが、2引数関数を渡す必要がある場合は、手動で行うことができます。

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)

これで、後で関数を取得するときに、パターンマッチを実行して、それがFunction2From3であるかどうかを確認し、値を読み取ることができます。

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.")
}

(整数であることが重要な場合はA、ジェネリックパラメーターとして削除して整数にすることができます。また、そのとき_1に呼び出すだけlowerでもかまいません)。

振り返り:いいえ、できません(一般的にはできません)。コンパイラはそれよりも賢い。生成されたバイトコード(コードをラップした場合class FuncApp)は次のとおりです。

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

iconst_3?に注意してください それはあなたの3が行ったところです-それはバイトコードに消えました。値を含む非表示のプライベートフィールドすらありません。

于 2011-03-16T18:35:39.400 に答える