Scala 自定义集合 returns null 列表作为默认值
Scala custom collection returns list of null as default values
我制作了一个名为 Matrix
的自定义集合,它以一维 List
的形式存储矩阵(这是一种要求,必须如此)。问题是,我想实现这个适用于泛型的集合。但是当我执行它并打印返回的集合时,它给出 null
值。
我创建了一个外部 class 来帮助自定义每种类型的默认值。
现在,片段:
输出:
> sbt run
[info] welcome to sbt 1.4.9 (N/A Java 15.0.2)
[info] loading project definition from /home/pace/Documents/git/1024-scala/1024-scala/project
[info] loading settings for project root from build.sbt ...
[info] set current project to scalatest-example (in build file:/home/pace/Documents/git/1024-scala/1024-scala/)
[info] compiling 1 Scala source to /home/pace/Documents/git/1024-scala/1024-scala/target/scala-2.13/classes ...
[info] done compiling
[info] running matrix.MainClass
Matrix(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null)
[success] Total time: 4 s, completed May 1, 2021, 9:10:28 PM
矩阵集合实现:
package matrix
import scala.collection.Iterable
import scala.collection.Iterator
import scala.collection.AbstractIterator
import defaultValues.Default
class Matrix[A] private (val col: Int, val row: Int, elems: List[A])
extends Iterable[A] { self =>
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
def this(s: Int) = this(col = s, row = s, elems = List.fill(s * s)(Default.value[A]))
def this(c: Int, r: Int) = this(col = c, row = r, elems = List.fill(c * r)(Default.value[A]))
def apply(i: Int): A = elems(i).asInstanceOf[A]
def iterator: Iterator[A] = new AbstractIterator[A] {
private var current = 0
def hasNext = current < elems.size
def next(): A = {
val elem = self(current)
current += 1
elem
}
}
override def className = "Matrix"
}
object MainClass extends App {
val m = new Matrix[Int]()
println(m)
}
以及我为每种类型获取 默认值 的方式(从其他 SO 线程获取,并且我检查过它在 Scala REPL
中有效):
package defaultValues
import scala.collection.immutable
class Default[+A](val default: A)
trait LowerPriorityImplicits {
// Stop AnyRefs from clashing with AnyVals
implicit def defaultNull[A <: AnyRef]: Default[A] = new Default[A](null.asInstanceOf[A])
}
object Default extends LowerPriorityImplicits {
implicit object DefaultString extends Default[String]("")
implicit object DefaultDouble extends Default[Double](0.0)
implicit object DefaultFloat extends Default[Float](0.0F)
implicit object DefaultInt extends Default[Int](0)
implicit object DefaultLong extends Default[Long](0L)
implicit object DefaultShort extends Default[Short](0)
implicit object DefaultByte extends Default[Byte](0)
implicit object DefaultBoolean extends Default[Boolean](false)
implicit object DefaultUnit extends Default[Unit](())
implicit def defaultSeq[A]: Default[immutable.Seq[A]] = new Default[immutable.Seq[A]](immutable.Seq())
implicit def defaultSet[A]: Default[Set[A]] = new Default[Set[A]](Set())
implicit def defaultMap[A, B]: Default[Map[A, B]] = new Default[Map[A, B]](Map[A, B]())
implicit def defaultOption[A]: Default[Option[A]] = new Default[Option[A]](None)
def value[A](implicit value: Default[A]): A = value.default
}
我是 运行 Scala 2.13
。
你能帮帮我吗?谢谢。
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
因为对 A
没有约束,您是在告诉编译器该函数应该适用于 every A
可能,这意味着 A
这里必须是 scala 中的最大类型 - AnyRef
。现在 A 被解析为 AnyRef
,Default.value[A]
总是解析为 defaultNull
,无论您在调用点放置什么。这是有道理的,因为你说它应该适用于所有可能的类型。
解决方案只是在 A 中放置一个约束,这样编译器就不会将其推断为最大类型:
class Matrix[A: Default] {
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
}
// equivalent to this form
def apply[A: Default]: Matrix[A] = new Matrix(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
// which is syntactic sugar for
def apply[A](implicit default: Default[A]): Matrix[A] = new Matrix(col = 4, row = 4, elems = ???
通过将约束放在那里,您可以将 A
的求解推迟到实际使用情况(调用 new Matrix[Int]
),因为现在编译器需要知道您拥有的实际 A
,以便它可以搜索隐式参数。
我制作了一个名为 Matrix
的自定义集合,它以一维 List
的形式存储矩阵(这是一种要求,必须如此)。问题是,我想实现这个适用于泛型的集合。但是当我执行它并打印返回的集合时,它给出 null
值。
我创建了一个外部 class 来帮助自定义每种类型的默认值。
现在,片段:
输出:
> sbt run
[info] welcome to sbt 1.4.9 (N/A Java 15.0.2)
[info] loading project definition from /home/pace/Documents/git/1024-scala/1024-scala/project
[info] loading settings for project root from build.sbt ...
[info] set current project to scalatest-example (in build file:/home/pace/Documents/git/1024-scala/1024-scala/)
[info] compiling 1 Scala source to /home/pace/Documents/git/1024-scala/1024-scala/target/scala-2.13/classes ...
[info] done compiling
[info] running matrix.MainClass
Matrix(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null)
[success] Total time: 4 s, completed May 1, 2021, 9:10:28 PM
矩阵集合实现:
package matrix
import scala.collection.Iterable
import scala.collection.Iterator
import scala.collection.AbstractIterator
import defaultValues.Default
class Matrix[A] private (val col: Int, val row: Int, elems: List[A])
extends Iterable[A] { self =>
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
def this(s: Int) = this(col = s, row = s, elems = List.fill(s * s)(Default.value[A]))
def this(c: Int, r: Int) = this(col = c, row = r, elems = List.fill(c * r)(Default.value[A]))
def apply(i: Int): A = elems(i).asInstanceOf[A]
def iterator: Iterator[A] = new AbstractIterator[A] {
private var current = 0
def hasNext = current < elems.size
def next(): A = {
val elem = self(current)
current += 1
elem
}
}
override def className = "Matrix"
}
object MainClass extends App {
val m = new Matrix[Int]()
println(m)
}
以及我为每种类型获取 默认值 的方式(从其他 SO 线程获取,并且我检查过它在 Scala REPL
中有效):
package defaultValues
import scala.collection.immutable
class Default[+A](val default: A)
trait LowerPriorityImplicits {
// Stop AnyRefs from clashing with AnyVals
implicit def defaultNull[A <: AnyRef]: Default[A] = new Default[A](null.asInstanceOf[A])
}
object Default extends LowerPriorityImplicits {
implicit object DefaultString extends Default[String]("")
implicit object DefaultDouble extends Default[Double](0.0)
implicit object DefaultFloat extends Default[Float](0.0F)
implicit object DefaultInt extends Default[Int](0)
implicit object DefaultLong extends Default[Long](0L)
implicit object DefaultShort extends Default[Short](0)
implicit object DefaultByte extends Default[Byte](0)
implicit object DefaultBoolean extends Default[Boolean](false)
implicit object DefaultUnit extends Default[Unit](())
implicit def defaultSeq[A]: Default[immutable.Seq[A]] = new Default[immutable.Seq[A]](immutable.Seq())
implicit def defaultSet[A]: Default[Set[A]] = new Default[Set[A]](Set())
implicit def defaultMap[A, B]: Default[Map[A, B]] = new Default[Map[A, B]](Map[A, B]())
implicit def defaultOption[A]: Default[Option[A]] = new Default[Option[A]](None)
def value[A](implicit value: Default[A]): A = value.default
}
我是 运行 Scala 2.13
。
你能帮帮我吗?谢谢。
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
因为对 A
没有约束,您是在告诉编译器该函数应该适用于 every A
可能,这意味着 A
这里必须是 scala 中的最大类型 - AnyRef
。现在 A 被解析为 AnyRef
,Default.value[A]
总是解析为 defaultNull
,无论您在调用点放置什么。这是有道理的,因为你说它应该适用于所有可能的类型。
解决方案只是在 A 中放置一个约束,这样编译器就不会将其推断为最大类型:
class Matrix[A: Default] {
def this() = this(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
}
// equivalent to this form
def apply[A: Default]: Matrix[A] = new Matrix(col = 4, row = 4, elems = List.fill(4 * 4)(Default.value[A]))
// which is syntactic sugar for
def apply[A](implicit default: Default[A]): Matrix[A] = new Matrix(col = 4, row = 4, elems = ???
通过将约束放在那里,您可以将 A
的求解推迟到实际使用情况(调用 new Matrix[Int]
),因为现在编译器需要知道您拥有的实际 A
,以便它可以搜索隐式参数。