В scala 3 есть свои context receivers и они не похожи на то что есть в Kotlin!
object PostConditions:
opaque type WrappedResult[T] = T
def result[T](using r: WrappedResult[T]): T = r
extension [T](x: T)
def ensuring(condition: WrappedResult[T] ?=> Boolean): T =
assert(condition(using x))
x
end PostConditions
import PostConditions.{ensuring, result}
val s = List(1, 2, 3).sum.ensuring(result == 6)
Разберу по строчкам:
opaque type WrappedResult[T] = T
: непрозрачный тип. Внутри объекта PostConditions компилятор "знает" что это один и тот же тип, снаружи смотрит на них как на два разных типа. Это не даст перепутать тип с типом обёртки, и, например, случайно присвоить одно в другое.
def result[T](using r: WrappedResult[T]): T = r
: функция, которая принимает неявный параметр откуда-то из контекста и возвращает его как нормальное значение.
extension [T](x: T):
def ensuring(condition: WrappedResult[T] ?=> Boolean): T = ....
extension метод, который принимает лямбду. Лямбда принимает неявный параметр, а метод ensuring его предоставляет.
val s = List(1, 2, 3).sum.ensuring(result == 6)
Метод списка sum
возвращает Int
, для него вызывается вышенаписанный метод ensuring, в который передаётся лямба. внутри лямбды есть неявный параметр и потому там (и только там, больше нигде) можно вызвать функцию result, которая вернёт этот самый T.
В коде где-либо снаружи PostConditions объект типа WrappedResult[T] не получится создать.