gpt4 book ai didi

scala - Dotty 提供什么来替换字体投影?

转载 作者:行者123 更新时间:2023-12-03 23:54:55 25 4
gpt4 key购买 nike

我一直在阅读有关 Dotty 的文章,因为它看起来即将成为 Scala 3,并注意到类型投影被认为是“不健全的”并从语言中删除......

这似乎很糟糕,因为我已经看到了几个非常有用的用例。例如:

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait Manager[T <: Container[_]] {
type ContainerType = T
type ContentType = T#ContentType
def getContents: ContentType
def createContainer(contents: ContentType): ContainerType
}

如何在 Dotty 中做这样的事情?向 Manager 添加第二个类型参数?但是,除了创建和操作 Manager 的实例变得非常乏味这一事实之外,它也不太有效,因为没有办法强制执行这两种类型之间的关系( Manager[FooContainer, Bar] 不应该是合法的)。

然后,还有其他用途,如类型 lambdas 和部分应用类型,可用于创建有偏差的仿函数等……或者这些(部分应用类型)是否成为 Dotty 中的“一等公民”?

编辑

为了回答评论中的问题,这里有一个有点人为的例子,可以使用他的 this 。假设,我的 Managers 实际上是 Akka Actors :
abstract class BaseManager[T <: Container[_]](
val storage: ContentStorage[T#ContentType]
) extends Actor with Manager[T] {
def withContents(container: T, content: ContentType): ContainerType
def withoutContents: T

var container: T = withoutContents

def receive: Receive {
case ContentsChanged =>
container = withContents(container, storage.get)
case ContainerRequester =>
sender ! container
// ... other common actions
}
}

class FooManager(storage: FooStorage) extends BaseManager[FooContainer](storage) {
def withContents(container: FooContainer, content: Foo) =
container.copy(Some(content))
def withoutContent = FooContainer(None)

override def receive: Receive = super.receive orElse {
// some additional actions, specific to Foo
}
}

case class FooContainer(content: Option[Foo]) extends Container[Foo]{
// some extremely expensive calculations that happen when
// content is assigned, so that we can cache the result in container
}

最佳答案

在 Scala 2.12 中,类型投影有时可以替换为类型类 + 依赖路径的类型

trait ContentType[T <: Container[_]] {
type Out
}
object ContentType {
type Aux[T <: Container[_], Out0] = ContentType[T] { type Out = Out0 }
def instance[T <: Container[_], Out0]: Aux[T, Out0] = new ContentType[T] { type Out = Out0 }

implicit def mk[T <: Contents]: Aux[Container[T], T] = instance
}

abstract class Manager[T <: Container[_]](implicit val contentType: ContentType[T]) {
type ContainerType = T
def getContents: contentType.Out
def createContainer(contents: contentType.Out): ContainerType
}

检查 Dotty 0.16.0-bin-20190529-3361d44-NIGHTLY(在 0.16.0-RC3 delegate 应该代替 implied )
trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait ContentType[T <: Container[_]] {
type Out
}
object ContentType {
implied [T <: Contents] for ContentType[Container[T]] {
type Out = T
}
}

trait Manager[T <: Container[_]] given (val contentType: ContentType[T]) {
type ContainerType = T
type ContentType = contentType.Out
def getContents: ContentType
def createContainer(contents: ContentType): ContainerType
}

另一种选择是使用 match types
trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

type ContentType[T <: Container[_]] = T match {
case Container[t] => t
}

trait Manager[T <: Container[_]] {
type ContainerType = T
def getContents: ContentType[T]
def createContainer(contents: ContentType[T]): ContainerType
}

关于scala - Dotty 提供什么来替换字体投影?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50043630/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com