Scala 3:Value作为类参数和Value Of

carvr3hs  于 2022-11-09  发布在  Scala
关注(0)|答案(1)|浏览(181)

我正在尝试将一个值指定为类参数:

import scala.collection.mutable

class MyMap[K,V,D <: V] {
  private val impl = mutable.Map[K, V]()
  def apply(k:K):V = impl.getOrElse(k, valueOf[D])
//                                     ^^^^^^^^^^ error
  def put(k:K,v:V):Unit = impl += k -> v
}

val m = MyMap[Int, Int, 0]()
m(100) // must return 0

出于某种原因,上述方法不起作用。取而代之的是下面这段不合逻辑的unusedName代码:

import scala.collection.mutable

class MyMap[K,V,D <: V] {
  private val impl = mutable.Map[K, V]()
  def apply(k:K)(implicit unusedName:ValueOf[D]):V = impl.getOrElse(k, valueOf[D])
  def put(k:K,v:V):Unit = impl += k -> v
}

val m = MyMap[Int, Int, 0]()
m(100) // must return 0

我试图明确地传递隐含的议论,理论上这应该是可能的,但它并没有像我预期的那样起作用:

scala> m(2)(0)
-- [E007] Type Mismatch Error: ----
1 |m(2)(0)
  |     ^
  |     Found:    (0 : Int)
  |     Required: ValueOf[(0 : Int)]

scala> m(2)(ValueOf[0])
-- Error: --------------------------
1 |m(2)(ValueOf[0])
  |     ^^^^^^^^^^
  |     missing arguments for constructor ValueOf in class ValueOf

scala> m(2)(ValueOf[0](0))
val res7: Int = 0

问题:

所有这些ValueOf/valueOf魔法是如何工作的?
为什么valueOf[D]不起作用?(这是合乎逻辑的)

更新

评论中引用的代码为:

import scala.collection.mutable

final class MyMap[K, V] private (default: V) {
  private val impl = mutable.Map.empty[K, V]

  def apply(k: K): V =
    impl.getOrElse(k, default)

  def put(k: K,v: V): Unit = {
    impl += k -> v
  }
}
object MyMap {
  def empty[K, V, D <: V](using ValueOf[D]): MyMap[K, V] =
    new MyMap(default = valueOf[D])
}

val m = MyMap.empty[Int, Int, 0]
m(100)

代码片段2:

import scala.collection.mutable

final class MyMap[K, V, D <: V](using ValueOf[D]) {
  private val default = valueOf[D]
  private val impl = mutable.Map.empty[K, V]

  def apply(k: K): V =
    impl.getOrElse(k, default)

  def put(k: K,v: V): Unit = {
    impl += k -> v
  }
}

val m = MyMap[Int, Int, 0]()
m(100)
2vuwiymt

2vuwiymt1#

所有这些魔法的价值是如何起作用的?
ValueOf[T]是存在T型的一个区别值的命题。
所有合理类型T的见证示例都由编译器自动生成。
对于每个v: ValueOf[T],成员访问v.value提供类型T的区别值。
方法valueOf[T]只是将见证者ValueOf[T]解压缩成T类型的值。
从头开始快速重建这一机制可能会有一定的启发意义:

case class MyValueOf[T](value: T)

// For ValueOf, these proofs are generated automatically by the compiler;
// Here, we have to do it ourselves
given MyValueOf[0] = MyValueOf(0)

def myValueOf[A](using mvo: MyValueOf[A]): A = mvo.value

println(summon[MyValueOf[0]]) // MyValueOf(0), the proof
println(myValueOf[0])         // 0, the value

为什么valueOf[D]不起作用?(这是合乎逻辑的)
因为,正如签名所说,方法valueOf[D]需要ValueOf[D]作为隐式参数。当D已知时,可以生成ValueOf[D]的示例。它不能为任意泛型类型D生成(如果是这样的话,那么您的代码可以为Map[Int, Int, Nothing]工作,这显然是荒谬的)。
关于你的REPL实验:

  • m(2)(0)显然不应该工作,因为0的类型是Int,而不是ValueOf[Int]
  • ValueOf[0]被解释为不完整的构造函数调用。如果您指的是类型而不是值,则必须使用summon来示例化类型的值,即m(2)(summon[ValueOf[0]])
  • ValueOf[0](0)基本上与要求summon[ValueOf[0]]时编译器生成的内容相同。

关于您的Map Package 器:
在创建贴图时,您可能希望传递一次默认值:

import scala.collection.mutable

class MyMap[K, V, D <: V](using defaultValueOf: ValueOf[D]) {
  private val impl = mutable.Map[K, V]()
  def apply(k: K): V = impl.getOrElse(k, valueOf[D])
  def put(k: K, v: V): Unit = impl += k -> v
}

val m = MyMap[Int, Int, 0]()
println(m(100)) // prints '0'

Package 器本身似乎没有太大帮助,因为已经在所有可变Map上定义了一个方法withDefault

相关问题