Reputation: 389
Im having troubles when trying to initialize an array with a generic type and storing it in a value (val)
case class Matrix[T <: AnyVal](val structure : Array[Array[Array[T]]])
//A method in another class
def foo() : Unit = {
val aux: Array[Array[Array[T]]] = Array.fill(this.structure.length, this.structure.head.length, this.structure.head.head.length)(null)
...
...
}
The problem is that, when trying to create an array of type T, I want to initialize it with a default value of null, but it says that:
Expression of type Array[Array[Array[T]]] doesn't conform to expected type Array[Array[Array[T]]]
How can I solve this problem? Thank you
Upvotes: 1
Views: 3197
Reputation: 5572
T:Numeric
If I were you I would restrict T
to Numeric
types and then use the zero
value as the default value for an empty matrix:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.reflect.ClassTag
class Matrix[T:Numeric](val structure: Array[Array[T]])
{
def *(that: Matrix[T]): Matrix[T] = ???
def +(that: Matrix[T]): Matrix[T] = ???
override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}
object Matrix
{
def apply[T:Numeric:ClassTag](rows: Int, cols: Int): Matrix[T] =
{
val zero: T = implicitly[Numeric[T]].zero
new Matrix[T](Array.fill[T](rows, cols)(zero))
}
def apply[T:Numeric](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}
// Exiting paste mode, now interpreting.
import scala.reflect.ClassTag
defined class Matrix
defined object Matrix
scala> val empty = Matrix[Int](3,3)
empty: Matrix[Int] =
0,0,0
0,0,0
0,0,0
scala> val ex = Matrix[Int](Array(Array(1,2), Array(3,4)))
ex: Matrix[Int] =
1,2
3,4
T <: AnyRef
Otherwise if you want to use non-numeric values with null
as default you can do something like this:
scala> :pa
// Entering paste mode (ctrl-D to finish)
import scala.reflect.ClassTag
class Matrix[T >: Null <: AnyRef](val structure : Array[Array[T]])
{
override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}
object Matrix
{
def apply[T >: Null <: AnyRef : ClassTag](rows: Int, cols: Int): Matrix[T] =
{
new Matrix[T](Array.fill[T](rows, cols)(null))
}
def apply[T >: Null <: AnyRef](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}
// Exiting paste mode, now interpreting.
import scala.reflect.ClassTag
defined class Matrix
defined object Matrix
scala> case class Person(name: String)
defined class Person
scala> val empty = Matrix[Person](3,3)
empty: Matrix[Person] =
null,null,null
null,null,null
null,null,null
scala> val data = Array(Array(Person("a"), Person("b")), Array(Person("c"), Person("d")))
data: Array[Array[Person]] = Array(Array(Person(a), Person(b)), Array(Person(c), Person(d)))
scala> val ex = Matrix[Person](data)
ex: Matrix[Person] =
Person(a),Person(b)
Person(c),Person(d)
Note that you must manually specify that T
can be a supertype of Null
by adding the bound T >: Null
.
Upvotes: 3
Reputation: 170899
If you want the default value, just use Array.ofDim(this.structure.length, this.structure.head.length, this.structure.head.head.length)
instead of Array.fill
. The values will be, like in Java, null
for objects, 0
for Int
, 0.0
for Double
, etc. It's cheaper as well.
You'll need a ClassTag[T]
in scope, but you need it for fill
as well.
Upvotes: 1