在对象中没有定义的类型声明的含义是什么? [英] What is the meaning of a type declaration without definition in an object?

查看:465
本文介绍了在对象中没有定义的类型声明的含义是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala允许使用type关键字定义类型,这些类型通常具有不同的含义和目的,具体取决于声明的时间.

Scala allows to define types using the type keyword, which usually have slightly different meaning and purpose depending on when they are declared.

如果在对象或包对象中使用type,则需要定义类型别名,即另一种类型的简称/简称:

If you use type inside an object or a package object, you'd define a type alias, i.e. a shorter/clearer name for another type:

package object whatever {
  type IntPredicate = Int => Boolean

  def checkZero(p: IntPredicate): Boolean = p(0)
}

在类/特征中声明的类型通常旨在在子类/子特征中被覆盖,并最终也解析为具体类型:

Types declared in classes/traits are usually intended to be overridden in subclasses/subtraits, and are also eventually resolved to a concrete type:

trait FixtureSpec {
  type FixtureType
  def initFixture(f: FixtureType) = ...
}

trait SomeSpec extends FixtureSpec {
  override type FixtureType = String

  def test(): Unit = {
    initFixture("hello")
    ...
  }
}

抽象类型声明还有其他用途,但无论如何最终它们都会解析为某些具体类型.

There are other uses for abstract type declarations, but anyway they eventually are resolved to some concrete types.

但是,还有一个选项可以在 object 内声明抽象类型(即没有实际定义):

However, there is also an option to declare an abstract type (i.e. without actual definition) inside an object:

object Example {
  type X
}

这会编译,而不是像抽象方法:

And this compiles, as opposed to e.g. abstract methods:

object Example {
  def method: String  // compilation error
}

由于无法扩展对象,因此永远无法将它们解析为具体类型.

Because objects cannot be extended, they can never be resolved to concrete types.

我假设这样的类型定义可以方便地用作幻像类型.例如(使用Shapeless的标记类型):

I assumed that such type definitions could be conveniently used as phantom types. For example (using Shapeless' tagged types):

import shapeless.tag.@@
import shapeless.tag

type ++>[-F, +T]

trait Converter

val intStringConverter: Converter @@ (String ++> Int) = tag[String ++> Int](...)

但是,似乎类型系统对待这些类型的方式与常规类型不同,这导致上述抽象"类型的使用在某些情况下会失败.

However, it seems that the way the type system treats these types is different from regular types, which causes the above usage of "abstract" types to fail in certain scenarios.

特别是,当寻找隐式参数时,Scala最终将查找与关联"类型关联的隐式范围,即在隐式参数的类型签名中存在的类型.但是,当使用抽象"类型时,这些关联类型的嵌套似乎存在一些限制.考虑以下示例设置:

In particular, when looking for implicit parameters, Scala eventually looks into implicit scope associated with "associated" types, i.e. types which are present in the type signature of the implicit parameters. However, it seems that there is some limitation on nesting of these associated types when "abstract" types are used. Consider this example setup:

import shapeless.tag.@@

trait Converter

type ++>[-F, +T]

case class DomainType()

object DomainType {
  implicit val converter0: Converter @@ DomainType = null
  implicit val converter1: Converter @@ Seq[DomainType] = null
  implicit val converter2: Converter @@ (Seq[String] ++> Seq[DomainType]) = null

}

// compiles
implicitly[Converter @@ DomainType]
// compiles
implicitly[Converter @@ Seq[DomainType]]
// fails!
implicitly[Converter @@ (Seq[String] ++> Seq[DomainType])]

在这里,前两个隐式解决方案可以很好地编译,而最后一个失败,并会出现有关缺少的隐式解决方案的错误.如果我在与implicitly调用相同的作用域中定义隐式函数,则它将编译:

Here, the first two implicit resolutions compile just fine, while the last one fails with an error about a missing implicit. If I define the implicit in the same scope as the implicitly call, it then compiles:

implicit val converter2: Converter @@ (Seq[String] ++> Seq[DomainType]) = null
// compiles
implicitly[Converter @@ (Seq[String] ++> Seq[DomainType])]

但是,如果我将++>定义更改为trait而不是type:

However, if I change the ++> definition to be a trait rather than type:

trait ++>[-F, +T]

然后上面的所有implicitly调用都可以编译.

then all implicitly calls above compile just fine.

因此,我的问题是,此类类型声明的确切目的是什么?它们打算解决什么问题?为什么不像对象中的其他抽象成员一样禁止使用它们?

Therefore, my question is, what exactly is the purpose of such type declarations? What problems they are intended to solve, and why are they not prohibited, like other kinds of abstract members in objects?

推荐答案

对于方法(或值),只有2个选项:它具有主体(然后为具体")或没有(然后为主体")它是抽象").类型X始终是某个类型间隔X >: LowerBound <: UpperBound(如果将LowerBound = UpperBound称为具体间隔,或者将LowerBound = NothingUpperBound = Any称为完全抽象,但它们之间的情况多种多样).因此,如果我们要禁止对象中使用抽象类型,则应该始终有办法检查LowerBoundUpperBound类型是否相等.但是可以用一些复杂的方式定义它们,通常这种检查并不容易:

For a method (or value) there are only 2 options: either it has body (and then it is "concrete") or it doesn't (then it is "abstract"). A type X is always some type interval X >: LowerBound <: UpperBound (and we call it concrete if LowerBound = UpperBound or completely abstract if LowerBound = Nothing, UpperBound = Any but there is variety of cases between those). So if we'd like to forbid abstract types in objects we should always have way to check that types LowerBound and UpperBound are equal. But they can be defined in some complex way and generally such check can be not so easy:

object Example {
  type X >: N#Add[N] <: N#Mult[Two] // Do we expect that compiler proves n+n=n*2?
}

这篇关于在对象中没有定义的类型声明的含义是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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