Когда я должен рассматривать свои методы как частично примененные функции в Scala? - PullRequest
26 голосов
/ 11 июля 2011

Я заметил, что когда я работаю с функциями, которые ожидают другие функции в качестве параметров, я иногда могу сделать это:

someFunction(firstParam,anotherFunction)

Но иногда компилятор выдает мне ошибку, сообщая, чтоЯ должен написать такую ​​функцию, чтобы она воспринималась как частично примененная функция:

someFunction(firstParam,anotherFunction _)

Например, если у меня есть это:

object Whatever {
    def meth1(params:Array[Int]) = ...
    def meth2(params:Array[Int]) = ...
}

import Whatever._
val callbacks = Array(meth1 _,meth2 _)

Почему можно 't У меня есть такой код:

val callbacks = Array(meth1,meth2)

При каких обстоятельствах компилятор скажет мне добавить _?

Ответы [ 3 ]

27 голосов
/ 11 июля 2011

Правило на самом деле простое: вы должны писать _ всякий раз, когда компилятор явно не ожидает объект Function.

Пример в REPL:

scala> def f(i: Int) = i    
f: (i: Int)Int

scala> val g = f
<console>:6: error: missing arguments for method f in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val g = f
               ^

scala> val g: Int => Int = f  
g: (Int) => Int = <function1>
6 голосов
/ 11 июля 2011

В Scala метод не является функцией.Компилятор может неявно преобразовывать метод в функцию, но он должен знать, какого рода.Так что вы либо используете _ для явного преобразования, либо можете указать, какой тип функции использовать:

object Whatever {
  def meth1(params:Array[Int]): Int = ...
  def meth2(params:Array[Int]): Int = ...
}

import Whatever._
val callbacks = Array[ Array[Int] => Int ]( meth1, meth2 )

или:

val callbacks: Array[ Array[Int] => Int ] = Array( meth1, meth2 )    
4 голосов
/ 11 июля 2011

В дополнение к тому, что сказал Жан-Филипп Пелле, вы можете использовать частично примененные функции при написании классов делегатов:

class ThirdPartyAPI{
   def f(a: Int, b: String, c: Int) = ...
   // lots of other methods
}

// You want to hide all the unnecessary methods
class APIWrapper(r: ThirdPartyAPI) {
   // instead of writing this
   def f(a: Int, b: String, c: Int) = r.f(a, b, c)
   // you can write this
   def f(a: Int, b: String, c: Int) = r.f _
   // or even this
   def f = r.f _
}

РЕДАКТИРОВАТЬ добавил def f = r.f _ часть.

...