函数定义中返回类型后的大括号 [英] Curly Parentheses After Return Type in Function Definition

查看:46
本文介绍了函数定义中返回类型后的大括号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读 cats 库时函子源码,没看懂toFunctorOps函数返回类型后面的curl块是干什么的;我的猜测是这个块将作为构造函数的一部分执行?如果是这样,那么为什么类型 TypeClassType 用相同的代码定义了两次 type TypeClassType = Functor[F]?

When read the cats library's Functor source, I could not understand what the curly block after the return type of the function toFunctorOps does; My guess is that this block will be executed as part of constructor? If so, then why type TypeClassType is defined twice with the same code type TypeClassType = Functor[F]?

  trait Ops[F[_], A] extends Serializable {
    type TypeClassType <: Functor[F]
    def self: F[A]
    val typeClassInstance: TypeClassType
    def map[B](f: A => B): F[B] = typeClassInstance.map[A, B](self)(f)
    ...
  }

  trait ToFunctorOps extends Serializable {
    implicit def toFunctorOps[F[_], A](target: F[A])(implicit tc: Functor[F]): Ops[F, A] {
      type TypeClassType = Functor[F]
    } =
      new Ops[F, A] {
        type TypeClassType = Functor[F]
        val self: F[A] = target
        val typeClassInstance: TypeClassType = tc
      }
  }

推荐答案

我不明白返回类型后面的卷曲块是什么......

I could not understand what the curly block after the return type ... does

细化{ type TypeClassType = Functor[F] } 进一步限制了特征Ops 的类型成员TypeClassType.换句话说,它向编译器提供了关于方法 toFunctorOps

The refinement { type TypeClassType = Functor[F] } puts a further constraint on type member TypeClassType of trait Ops. In other words it gives more information to the compiler about the specific return type of method toFunctorOps

Ops[F, A] { type TypeClassType = Functor[F] }

注意细化块被认为是返回类型的部分,与构造函数无关.

Note the refinement block is considered part of the return type and has nothing to do with the constructor.

让我们简化类型以更好地说明概念,所以考虑

Let us simplify the types to illustrate the concept better, so consider

trait Foo {
  type A
  def bar: A
}

val foo: Foo = new Foo { 
  type A = Int 
  def bar: A = ???
}
val x: foo.A = 42 // type mismatch error

注意变量 foo 的静态类型如何不包括类型成员 A 已实例化为 Int 的特定信息.现在让我们使用类型细化向编译器提供这些信息

Note how static type of variable foo does not include specific information that type member A has been instantiated to Int. Now let's give the compiler this information by using type refinement

val foo: Foo { type A = Int } = new Foo { 
  type A = Int
  def bar: A = ??? 
}
val x: foo.A = 42 // ok

现在编译器知道类型成员 A 正是一个 Int.

Now compiler knows that type member A is precisely an Int.

类型类的设计者在何时使用类型成员而不是类型参数方面做出明智的决定,有时甚至在您的情况下两者混合使用.例如特征 Foo 可以像这样被参数化

Designers of type classes make judicious decisions regarding when to use type members as opposed to type parameters, and sometimes there is even a mix of the two as in your case. For example trait Foo could have been parameterised like so

trait Foo[A] {
  def bar: A
}
val foo: Foo[Int] = new Foo[Int] { 
  def bar: Int = ??? 
}

并且编译器将再次获得类型参数 A 已实例化为 Int 的精确信息.

and compiler would again have precise information that type parameter A has been instantiated to Int.

为什么 TypeClassType 定义了两次

why type TypeClassType is defined twice

细化类型 Foo { type A = Int }Foo 的一个更窄的子类型,类似于 Cat 是一个更窄的子类型动物

The refined type Foo { type A = Int } is a narrower subtype of Foo, similar to how Cat is a narrower subtype of Animal

implicitly[(Foo { type A = Int }) <:< Foo]
implicitly[Cat <:< Animal]

因此,即使右侧表达式将 A 实例化为 Int,左侧表达式也明确告诉编译器 foo<的静态类型/code> 只是更广泛的超类型 Foo

so even though the right-hand side expression instantiates A as Int, the left-hand side explicitly told the compiler that the static type of foo is just the wider supertype Foo

val foo: Foo = new Foo { 
  type A = Int 
  def bar: A = ???
}

类似于编译器如何知道下面的 zar 静态类型只是更广泛的超类型 Animal 尽管 RHS 上的表达式指定了 Cat

similarly to how compiler knows that static type of zar below is only the wider supertype Animal despite the expression on the RHS specifying a Cat

val zar: Animal = new Cat

因此需要双重"类型说明

Hence the need for "double" type specification

val foo: Foo { type A = Int } = new Foo { 
  type A = Int 
  ...
}

类似

val zar: Cat = new Cat

我们可以尝试依靠推理来推断出最具体的类型,但是当我们显式注释类型时,我们必须通过细化提供包括类型成员约束的完整信息.

We could try to rely on inference to deduce the most specific type, however when we are explicitly annotating types then we have to provide the full information which includes the type member constraints via refinements.

这篇关于函数定义中返回类型后的大括号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆