Можно ли в Scala сделать наоборот?

Предположим, что эта функция:

def autoClosing(f: {def close();})(t: =>Unit) = {
    t
    f.close()
}

и этот фрагмент:

val a = autoClosing(new X)(_)
a {
 println("before close")
}

можно ли прокачать первую часть? Что-то типа:

val a = autoClosing(_) { println("before close") }

чтобы я мог отправить объекты, над которыми должно быть выполнено закрытие, и выполнить на них тот же блок?


person Geo    schedule 17.12.2009    source источник


Ответы (3)


Да, приведенный вами фрагмент работает, если вы указываете тип символа-заполнителя.

Таким образом, код, который вы ищете:

val a = autoClosing(_: {def close();}) { println("before close") }

который компилируется и работает как положено :).

Пара замечаний:

  • Вы можете облегчить себе жизнь, если определите псевдоним типа для типа AnyRef, имеющего метод close, что-то вроде type Closeable = AnyRef {def close()} или соответствующий интерфейс.
  • Фрагмент кода autoClosing(_: Closeable){ ... } фактически эквивалентен следующей расширенной анонимной функции: c: Closeable => autoClosing(c){ ... }. Подстановочный знак — это просто сокращение для частично примененной функции. Вам нужно указать тип _, поскольку в этом случае вывод типа, к сожалению, не может вывести тип.

Надеюсь, поможет,

-- Флавиу Сипиган

person Flaviu Cipcigan    schedule 17.12.2009
comment
Пожалуйста. Добавил пару заметок, чтобы расширить свой ответ :). К сожалению, механизм вывода типа не может здесь вывести тип подстановочного знака. - person Flaviu Cipcigan; 17.12.2009

В качестве альтернативы вы можете перевернуть параметры:

def flip[A1, A2, B](f: A1 => A2 => B): A2 => A1 => B = x1 => x2 => f(x2)(x1)

В твоем случае:

val a = flip(autoClosing){ println("before close") }

Изменить: я добавил несколько фигурных скобок, чтобы помочь человеческому парсеру:

def flip[A1, A2, B](f: (A1 => (A2 => B))): (A2 => (A1 => B)) = {
    x1 => (x2 => f(x2)(x1))
}

Flip преобразует функцию (A1 => (A2 => B)) в (A2 => (A1 => B)).

scala> def x(x1 : Int)(x2 : Long) = 1.0 * x1 / x2
x: (Int)(Long)Double

scala> val f = flip(x)
f: (Long) => (Int) => Double = <function>

scala> val g = f(1)
g: (Int) => Double = <function>

scala> val h = g(2)
h: Double = 2.0

scala> x(1)(2)
res0: Double = 0.5
person Thomas Jung    schedule 17.12.2009
comment
Не могли бы вы немного объяснить этого монстра? :) - person Geo; 17.12.2009
comment
Я добавил несколько фигурных скобок и пример кода, чтобы увидеть частичное приложение в действии. Надеюсь это поможет. - person Thomas Jung; 17.12.2009

Я рад, что сегодня так много людей отвечает на вопросы о Scala. Однако мне трудно что-то придумать. Вот альтернатива Flaviu решение.

val a: {def close();} => Unit = autoClosing(_) { println("before close") }

Конечно, правильное решение — определить autoClosing таким образом, чтобы он был совместим с тем, как вы собираетесь его использовать.

person Daniel C. Sobral    schedule 17.12.2009
comment
Я тоже этому рад :). Я отказываюсь от Ruby в пользу Scala... в этом языке есть все, что я хотел. - person Geo; 17.12.2009