Как сделать так, чтобы компилятор Scala выводил один тип из другого? - PullRequest
2 голосов
/ 03 апреля 2012

Я хочу создать класс типов Scala Id, чтобы, например, я мог объявить, что Id для типа Foo принимает значение Long, например,

val fooId: Id[Foo] = Id(12L) // type-safe at compile time
val fooIdValue: Long = fooId.value // able to get the value back out

Я пробовал разные способы, но яне может обеспечить соблюдение ограничений.Если я объявляю

trait WithId[I] {
  type Id = I
}

case class Id[A <: WithId[_]](value: A#Id) // A#Id => Any, not what I want!

class Foo extends WithId[Long] {
  type Id = Long
}

, это позволяет

val fooId: Id[Foo] = Id("foo") // should be illegal unless a Long

Если я изменяю WithId для использования абстрактного типа

trait WithId {
  type Id
}

case class Id[A <: WithId](value: A#Id)

class Foo extends WithId {
  type Id = Long
}

, тогда

val fooId: Id[Foo] = Id(12L)

не компилируется, говоря

no type parameters for method apply: (value: A#Id)net.box.Id[A] in object Id exist so that it can be applied to arguments (Long)  --- because --- argument expression's type is not compatible with formal parameter type;  found   : Long  required: ?0A#Id

Как я могу сказать, что Id [Foo] занимает Long?

1 Ответ

3 голосов
/ 03 апреля 2012

Вы правы, что избавились от этого параметра типа на WithId. Однако вторая проблема возникает из-за того, как вы создаете экземпляр Id. Когда вы говорите val x: Foo[T], вы указываете, какой тип вы хотите иметь x, но на самом деле вы не помогаете компилятору выяснить, какой тип Foo следует использовать при его создании. Итак ... ошибка компилятора, которую вы получаете, когда вы говорите Foo, что вы хотите Id из A, но вы не сказали Foo что такое A даже! Чтобы это исправить, просто измените ваше использование на

val fooId = Id[Foo](12L)
...