2011-01-07 24 views
5

Estoy tratando de definir una interfaz de colección personalizada en Scala 2.8. Quiero exigir que las subclases sean Traversables, más algún otro comportamiento. También quiero métodos como el mapa() para devolver el tipo apropiado, de la siguiente manera:¿Cómo puedo definir una interfaz de colección personalizada en Scala sin definir una implementación?

trait CustomCollection[+A] extends Traversable[A] { 
    def customOperation(i:Int):Int // for example 
} 

def incrementAll(c:CustomCollection[Int]):CustomCollection[Int] = c.map { _ + 1 } 

Esto no compila, porque CustomCollection.map() devuelve una de Traversable. Supongo que necesito definir un CanBuildFrom, pero luego necesito definir un método apply() que construya una instancia desde cero. No quiero especificar una forma de construir esto; eso debería estar a cargo del implementador. es posible?

Respuesta

5

Si desea map para devolver un tipo de colección más específica, entonces también debe heredar TraversableLike, con el segundo parámetro de tipo (tipo de representación) ajustado en CustomCollection[A].

Siguiente, map requiere un parámetro implícito del tipo CanBuildFrom. Buscará en el objeto complementario de CustomCollection para encontrar un valor implícito conforme de ese tipo. Si echa un vistazo al código fuente de las clases Seq, verá que sus compañeros proporcionan CanBuildFrom objetos del tipo GenericCanBuildFrom que reenvía la llamada para el generador de vuelta a la colección que solicitó el constructor. De esta forma, el tipo dinámico de tipo de retorno de los métodos del transformador Seq (por ejemplo, map) es siempre el mismo que el tipo de la secuencia en sí.

Lo que tienes que hacer es:

  1. Hacer CustomCollection[A] hereda TraversableLike
  2. Hacer CustomCollection[A] heredan GenericTraversableTemplate
  3. Hacer un objeto acompañante de CustomCollection y añade una implícita que devuelve un GenericCanBuildFrom
  4. Proporcionar una implementación predeterminada para el constructor en el CustomCollection

Los ejecutores de CustomCollection tendrán que proporcionar objetos de compañía que tienen implementaciones constructor e implícitos CanBuildFrom objetos (que puede ser simplemente GenericCanBuildFrom s).

EDIT:

GenericTraversablTemplate mencionado anteriormente es necesaria, ya que primero se asegura de que la colección tendrá el método genericBuilder llamado por la fábrica GenericCanBuildFrom constructor. En segundo lugar, garantiza que la colección en realidad tenga el objeto complementario del tipo GenericCompanion.

+0

Gracias, axel22. Si entiendo su respuesta, debo proporcionar una implementación predeterminada de CustomCollection, que será utilizada por el método newBuilder de mi compañero. Esperaba evitar especificar una implementación predeterminada. ¿Podría explicarme por qué lo necesito? No parece que deba ser necesario para un método como map(), porque no puede llamar a map() a menos que ya tenga alguna implementación. – traversable

+1

Técnicamente, podría evitar proporcionar una implementación de constructor predeterminada en el acompañante 'CustomCollection', pero ¿cómo implementar el método' apply() 'sin parámetros en' CanBuildFrom'? Puede permitir que 'newBuilder' en el compañero' CustomCollection' arroje una excepción de operación no admitida, evitando así una implementación predeterminada.Creo que todo funcionaría, excepto el método 'breakOut' en colecciones, que requiere el parámetro' apply() '.. – axel22

+0

Ah ... así que la razón por la que necesito una implementación predeterminada es hacer que breakOut funcione. ¡Gracias! – traversable

Cuestiones relacionadas