这里有人说星号是scala 3的下划线,但是我在scala 2.13中看到了一些类似的代码:
def make[F[_]: ContextShift: MonadError[*[_], Throwable]: Effect: Logging](): ...
它是否具有相同的含义,仅在*中指定类型与_中的类型不同?
_
表示(取决于上下文)
def foo[F[_]]: Unit
def bar(f: F[_]): F[_]
在这里我们想了解类型构造器。
类型构造函数将(简化)F
某种尚未定义的东西,但我们可以将A
其应用于并将其设为F[A]
。例如
List
可以通过,F[_]
因为它有空隙,如果我们用它填充,例如,String
它可以变成List[String]
Option
也可以通过F[_]
,它有一个空白,如果我们用Int
它填充,它将变成Option[Int]
Double
不能用作F[_]
,因为它没有间隙具有“空白”的类型通常表示为* -> *
,而没有“ gap”的类型通常表示为*
。我们可以*
简单地将其理解为类型,而可以理解* -> *
为“需要另一个类型构成类型的类型”或类型构造函数。
(像上面提到的那种类型更高级的类型本身就是复杂的事情,因此,您最好在该问题之外进一步了解它们)。
*
(来自kindprojector插件)用于同类投影-语法是从上面的符号启发而来的,它显示了如果我们要创建新类型,将在哪里传递类型:
Monad[F[List[*]]]
真的像:
type UsefulAlias[A] = F[List[A]]
Monad[UsefulAlias]
除了它在没有类型别名的情况下工作之外。
如果是Dotty,最好用lambda类型表示:
// Monad[F[List[*]]] is equal to
[A] =>> Monad[List[A]]
在您的示例中:
def make[F[_]: ContextShift: MonadError[*[_], Throwable]: Effect: Logging](): ...
F[_]
被定义为类的构造函数-这样你就可以不通过有String
,Int
或Byte
,但你可以通过那里List
,Future
或者Option
(因为他们把一个类型参数)F[_]: ContextShift
是-的快捷方式[F[_]](implicit sth: ContextShift[F])
-我们可以看到ContextShift
将某种类型的参数作为参数作为参数(例如F[_]
)[F[_]: MonadError[*[_], Throwable]
可以扩展为: type Helper[G[_]] = MonadError[G, Throwable]
[F[_]: Helper]
反过来可以改写为 type Helper[G[_]] = MonadError[G, Throwable]
[F[_]](implicit me: Helper[F])
或使用lambda类型 [F[_]] =>> MonadError[F, Throwable]
如果将其编写为:
def make[F[_]: ContextShift: MonadError[*, Throwable]: Effect: Logging]():
问题是,这*
表明预期类型为
[A] =>> MonadError[A, Throwable]
同时*
应该* -> *
代替*
。因此,这*[_]
意味着“我们要在此处通过用一个东西代替*
参数来创建一个新的类型构造函数,但是我们要表示该参数是实物* -> *
而不是实物*
[F[_]] =>> MonadError[F, Throwable]
因此,我们将添加[_]
以向编译器显示它是类型构造函数。
需要吸收很多东西,应该更容易些,我只能感到抱歉,并说在Dotty中会更清楚。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句