Home > front end >  Scala: How to pattern match a class type that extends a parent class?
Scala: How to pattern match a class type that extends a parent class?

Time:02-21

I'm trying to use pattern matching to match classes that extend from a parent class, but also restrict the classes you can pass as a parameter using classType: Class[_ <: Animal]. Here's an example:

  class Animal
  class Dog extends Animal
  class Cat extends Animal

  def returnAnimalSubtypeObject(classType: Class[_ <: Animal]): Animal = {
    classType match {
      case _: Dog => new Dog()
      case _: Cat => new Cat()
    }
  }

  returnNewClass(Class[Dog])

But this returns the following error message:

<console>:16: error: pattern type is incompatible with expected type;
 found   : Dog
 required: Class[_$1] where type _$1 <: Animal
             case _: Dog => new Dog()

I think I'm not understanding something fundamental here since I'm still a beginner. Could someone explain what's the best approach to solving this?

CodePudding user response:

The Class object for Dog is not a Dog: it's a Class.

With the proviso that there's almost certainly a better way to accomplish what you actually want to do, you could:

def returnAnimalSubtypeObject(clazz: Class[_ <: Animal]): Animal =
  if (clazz == classOf[Dog]) new Dog()
  else if (clazz == classOf[Cat]) new Cat()
  else new Animal()

CodePudding user response:

It seems like you are trying to implement something like ADT(Abstract Data Type). I would prefer to use sealed trait or sealed abstract class since it's better in pattern matching.

see also: https://nrinaudo.github.io/scala-best-practices/definitions/adt.html

  sealed trait Animal
  case class Dog(name: String, bark: Boolean) extends Animal
  case class Cat(name: String, mow: Boolean) extends Animal

  object Animal {
    def returnAnimalSubtypeObject(x: Animal): Animal = x match {
      case d: Dog => d
      case c: Cat => c
    }
  }


scala> Animal.returnAnimalSubtypeObject(Dog("a dog can bark", true))
val res2: Animal = Dog(a dog can bark,true)

scala> Animal.returnAnimalSubtypeObject(Cat("a cat can mow", true))
val res3: Animal = Cat(a cat can mow,true)

When we use sealed keywork, the Scala compiler will check the pattern match is exhaustive or not.

// if we miss a type to match
def returnAnimalSubtypeObject(x: Animal): Animal = x match {
      case d: Dog => d
    }

// it will show warning.
 match may not be exhaustive.
[warn] It would fail on the following input: Cat(_, _)
[warn]     def returnAnimalSubtypeObject(x: Animal): Animal = x match {
[warn]                                                        ^
[warn] one warning found
  • Related