I'm learning Scala 3, and I was intrigued by match types and literal types.
I'd like to write a function that takes one of a few literal types, and returns a particular type as a function of which literal type was passed in.
Here's a fairly minimal example of what I'm trying to do:
type TestMatchType[T] = T match
case "String1" => Int
case "String2" => String
def testMatchType[T](input: T): TestMatchType[T] =
input match
case "String1": "String1" => 1
case "String2": "String2" => "Two"
val string1Output: Int = testMatchType("String1")
In words:
testMatchType
, which takes an argument whose type is either the type literal "String1"
, or the type literal "String2"
. If an argument with type "String1"
is passed, the function should return an Int
. If an argument with type "String2"
is passed, the function should return a String
. If an argument is passed whose type is not one of these type literals, a compile-time error is produced."However, when I try to compile the above code, I get the following error:
1 |val string1Output: Int = testMatchType("String1")
| ^^^^^^^^^^^^^^^^^^^^^^^^
| Found: TestMatchType[String]
| Required: Int
|
| Note: a match type could not be fully reduced:
|
| trying to reduce TestMatchType[String]
| failed since selector String
| does not match case ("String1" : String) => Int
| and cannot be shown to be disjoint from it either.
| Therefore, reduction cannot advance to the remaining case
|
| case ("String2" : String) => String
I'm trying to grok that error message. I'm struggling to understand the line "selector String does not match case ("String1" : String) => Int
". I would love some advice if there's a way to make this work.
Thank you!
You don't need to use "foo": "foo"
, just use _: "foo"
.
However, the error happens because T
will not be inferred as a singleton type, so the return type will never be Int
or String
either, it'll remain TestMatchType[String]
. You'll either have to use T <: Singleton
or use input.type
as an argument to TestMatchType
(I prefer the latter).
def testMatchType[T](input: T): TestMatchType[input.type] =
input match
case _: "String1" => 1
case _: "String2" => "Two"