scala - andthen - ¿Por qué el andthhen of future no encadena el resultado?
scala future andthen example (2)
El significado de andThen
que aprendí de esta answer es un compositor de funciones.
Dilo
f andThen g andThen h
será igual a
h(g(f(x)))
Esto implica que la h function
recibirá entrada de g(f(x))
Pero para el y andThen
en el Future
, todo el cierre de lo siguiente y luego siempre recibe el resultado del Future
original.
Future{
1
}.andThen{ case Success(x) =>
println(x) // print 1
Thread.sleep(2000)
x * 2
}.andThen{ case Success(x) =>
println(x) // print 1
Thread.sleep(2000)
x * 2
}
comparar con
val func: Function1[Int, Int] = { x: Int =>
x
}.andThen { y =>
println(y) // print 1
y * 2
}.andThen { z =>
println(z) // print 2
z * 2
}
func(1)
¿Cuál es la razón para hacer que Future :: andThen (s) reciba el mismo resultado del Future original en lugar de encadenar Future? He observado que estos encadenados y, a continuación, se ejecutarán secuencialmente, por lo que la razón puede no ser para propósitos paralelos.
Déjame resumir esta buena discusión.
Digamos que tenemos tf: Future[T] =...
, y dos funciones, f: T => U
y g: U => V
Podemos hacer vf: Future[V] = tf map f map g
, igual que vf: Future[V] = tf map (f andThen g)
En otro caso de uso, teniendo fp: PartialFunction[T, U]
y gp: PartialFunction[U, V]
, podemos ejecutar tf1: Future[T] = tf andThen fp andThen gp
- estas funciones parciales se tf1: Future[T] = tf andThen fp andThen gp
en el valor que tf produce, sin efectos externos, solo ocurren los efectos secundarios. Esta secuencia espera a fp
antes de llamar a gp
.
Otra operación futura, onComplete, funciona así: al tener f: Try[T] => U
, la llamada tf onComplete f
llamará f
incluso si el futuro finaliza con un error; el resultado de tf onComplete f
es de tipo Unit
.
Además, si su función f
produce un Future
, necesitará usar flatMap
.
scala.concurrent.Future
está diseñado como compromiso de dos enfoques asíncronos:
- observer orientado a objetos que permite la vinculación de manejadores asíncronos.
- monad funcional que ofrece una rica capacidad de composición funcional.
Leyendo el Future.andThen
los documentos :
Aplica la función de efecto secundario al resultado de este futuro y devuelve un nuevo futuro con el resultado de este futuro.
Entonces andThen
lo más probable es que sea del universo OOP. Para obtener un resultado similar al de Function1.andThen
puede usar el método de map
:
Future(1).map {_ * 2}.map {_ * 2}
andThen
difiere de onComplete
con una pequeña cosa: el futuro resultante de y andThen
sigue devolviendo el mismo resultado, pero esperará hasta que el observador provisto devuelva o arroje algo. Es por eso que está escrito en los documentos:
Este método permite imponer que las devoluciones de llamada se ejecutan en un orden específico.
También tenga en cuenta la tercera línea de documentos:
Tenga en cuenta que si una de las devoluciones de llamada encadenada y luego emite una excepción, esa excepción no se propaga a las devoluciones de llamada subsiguientes y posteriores. En su lugar, las devoluciones de llamada subsiguientes y, a continuación, reciben el valor original de este futuro.
Así que no hace nada con el nuevo resultado del Future
. Ni siquiera podía estropearlo con su propia excepción. Esto y, a andThen
y onComplete
solo la unión secuencial y paralela de observadores.