问题
I would like to parameterize a type with one of its subclasses. Consider the following:
class DataLoader {
class Data { /* data specifics to this data loader */ }
def getData : Data /* and so on */
}
Now I want to make this loader able to asynchronously retrieve data from the network. One of the options is to have it subclass Callable.
class DataLoader extends Callable[Data] {
class Data { /* ... */ }
def call : Data = { ... }
}
val futureData = executor.submit(new DataLoader)
futureData.get
Scala will not let me do that, because when I supply the parameters of Callable, Data is not known yet. If I write DataLoader.Data, Scala calls me off for a cyclic reference.
Sure, I could write my data class outside of my loader, but there are cases where it's nicer inside. Sure, another alternative would be to have, say, a DataManager, with inside a Data type and a Loader which extends Callable[Data] - which in this case is arguably better design. But those issues aside, is there any way I can actually implement a trait that involves writing a function returning a T, setting T to be an inner class ?
回答1:
There are a million ways to achieve something reasonable, so it's hard to know how to answer. I don't think you want to get too attached to the idea of parameterizing a supertype on one of the subtype's own inner classes. Even if it works, it won't.
Out of the million ways I picked something at random and it turned out to involve inversion. I did it this way because you said in a comment you couldn't get it to compile in the companion object, and I'm not sure why that would be.
import java.util.concurrent.Callable
class DataLoader extends Callable[DataLoader.Data] {
def call = new DataLoader.Data(this)
}
object DataLoader {
private class Data(loader: DataLoader) {
}
}
回答2:
What about this?
trait Callable {
type TData
def getData: TData
}
class DataLoader extends Callable {
type TData = Data
class Data
override def getData: TData = new Data
}
Edit:
Sorry, didn't notice you meant the Callable from java.util.concurrent.. Then adding the following might help:
implicit def c2c[T](c: Callable {type TData = T}) = new java.util.concurrent.Callable[T] {
def call = c.getData
}
回答3:
Put the class inside the object companion.
来源:https://stackoverflow.com/questions/3920658/scala-parameterize-a-type-with-one-of-its-inner-types