Странный синтаксис Scala, в котором Future отображается так, что «==» и «! =» Появляются только с одним операндом (не двумя) - PullRequest
0 голосов
/ 21 сентября 2018

Я натолкнулся на загадочную, но интересную кодовую конструкцию, которую я сократил до небольшого примера, и мне все еще не удается обернуть голову.

Пример показан ниже.Обратите внимание, что у меня есть простое будущее, которое немедленно возвращает строкуЯ сопоставляю это с сравнением самого Будущего, используя! = И ==

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Dummy extends App {
  val taskReturningString: Future[String] =  Future{ "foo"}

  val falseResult: Future[Boolean] = taskReturningString.map(taskReturningString ==)
  System.out.println("false result:" + Await.result(falseResult, 0 nanos) )

  val trueResult: Future[Boolean] = taskReturningString.map(taskReturningString !=)
  System.out.println("true result:" + Await.result(trueResult, 0 nanos) )
}

Вывод

    false result:false
    true result:true

Но я не уверен, почему я получил эти результаты.В случае == и! = Первым сравниваемым элементом является 'taskReturningString' - Future.Но с чем это сравнивается?Я предполагаю, что происходящее является сравнением, но я никогда не видел случая, чтобы операторы == и! = Появлялись с одним операндом вместо двух.

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Ответ на этот вопрос заключается в следующих фактах:

Факт 1: Даже операторы methods в Scala,

// something like
val a = "abc" == "def"

// is actually
val a = "abc".==("def")

Итак, taskReturningString == на самом деле метод taskReturningString.==

Факт 2: methods можно преобразовать в functions (с помощью _),

val string1 = "abc"

val func1 = string1.== _
// func1: Any => Boolean = sof.A$A0$A$A0$$Lambda$1155/266767500@12f02be4

// or if you want more specific type,
val func2: String => Boolean = string1.== _
// func2: String => Boolean = sof.A$A0$A$A0$$Lambda$1156/107885703@19459210

Факт 3: Компилятор Scala является интеллектуальным.Он поддерживает eta-expansion, который является преобразованием method в соответствующий function (чтобы соответствовать требованию) (если возможно).Итак, если мы сообщим компилятору, что нам нужен Function типа String => Boolean, и дадим ему метод, он умно преобразует его в функцию.

// so our func3 did not need that explicit conversion using `_`

val func3: String => Boolean = string1.==
// func3: String => Boolean = sof.A$A1$A$A1$$Lambda$1161/1899231632@4843e7f0

Теперь, поскольку ваш taskReturningStringFuture[String], таким образом, taskReturningString.map хочет функцию типа String => A для любого типа A.

Кроме того, taskReturningString.== принимает аргумент типа Any и тип возврата Boolean,

компилятор расширит его до функции String => Boolean,

val future1 = Future("abc")

val func4: String => Boolean = future1.==
// func4: String => Boolean = sof.A$A4$A$A4$$Lambda$1237/1577797787@2e682ccb

// And since `func4` will compare the argument string with `future1` for equality
// it will always return `false`

// So what you are doing is actually,
val falseResult: Future[Boolean] = future1.map(func4)
0 голосов
/ 21 сентября 2018

Такое поведение связано с eta expansion.Этим map нужна функция String => Boolean (потому что вывод типа), а taskReturningString == - это метод, который можно расширить до такого рода функции.

Вот упрощенный пример.

val equals: String => Boolean = "foo" ==

println(equals("foo"))
// true

println(equals("bar"))
// false

или с +

val plusTwo: Int => Int = 2 +
println(plusTwo(2))
// 4

drop из String

val drop: Int => String =  "abcd".drop
println(drop(2))
// cd

или ::: из списка

val concat: List[Int] => List[Int] = List(1,2,3) :::
println(concat(List(4,5,6)))
// List(4,5,6,1,2,3)

Использование_ не всегда необходим, если компилятор понимает, что он может расширить метод с отсутствующими параметрами, и типы являются правильными.

Этот код не работает, потому что компилятор не может знать тип equals

val equals = "foo" ==

, поэтому мне нужно помочь с _

val equals = "foo" == _
...