2017-09-16 5 views
0

Je suis relativement nouveau dans la programmation Scala. En dehors de Scala, je n'ai jamais appris la programmation fonctionnelle. Cela dit, j'essaie actuellement de trouver un bon moyen de définir les traits, les classes, etc., sur un projet utilisant Slick. Mon idée était d'avoir un trait ayant les méthodes à implémenter sur les classes enfant, et certaines seraient implémentées sur la classe parente elle-même. J'ai trouvé un moyen qui fonctionne mais je ne sais pas pourquoi. Je ne sais pas si ce problème est lié au fonctionnement de Slick ou Scala.Utilisation du type TableQuery générique sur le trait parent

j'utilisais une construction comme:

trait CompanyDAO extends BaseDao[Company]{ 
self: DBProfile => 

Mais cela donne l'erreur d'incompatibilité de type:

[error] found : slick.lifted.TableQuery[CompanyDAO.this.CompanyTable] [error] required: slick.lifted.TableQuery[CompanyDAO.this.profile.api.Table[Company]] [error] (which expands to) slick.lifted.TableQuery[CompanyDAO.this.profile.Table[Company]] [error] Note: CompanyDAO.this.CompanyTable <: CompanyDAO.this.profile.api.Table[Company], but class TableQuery is invariant in type E. [error] You may wish to define E as +E instead. (SLS 4.5) [error] override def toTable = TableQuery[CompanyTable]

Mais, si j'utilise

self: DBProfile with BaseDao[Company] => 

Ensuite, les travaux de compilation (BTW, a obtenu la solution de another post)

Alors, mes questions:

1) Pourquoi l'utilisation de self-types toTable fonctionne tout en n'étendant pas le trait? Comment scala interprète le type de toTable dans les deux scénarios?

2) Existe-t-il un moyen d'adapter le "trait CompanyDAO extends BaseDao" pour résoudre l'erreur?

Merci d'avance.

import scala.concurrent.Future 
import slick.basic.DatabaseConfig 
import slick.jdbc.JdbcProfile 

trait DBConfiguration { 
    lazy val config = DatabaseConfig.forConfig[JdbcProfile]("mytrade") 
} 

trait DBProfile { 
    val config: DatabaseConfig[JdbcProfile] 
    val db: JdbcProfile#Backend#Database = config.db 
    val profile : JdbcProfile = config.profile 
} 

trait BaseDao[T <: Any] { 
    self: DBProfile => 

    import profile.api._ 
    import slick.lifted.TableQuery 

    def toTable():TableQuery[Table[T]] 
    def findAll():Future[Seq[T]] = db.run(toTable.result) 
} 

case class Company(name: String, code: Int) 

// If I use the construction like the comment below, it will fail 
//trait CompanyDAO extends BaseDao[Company]{ 
    //self: DBProfile => 

trait CompanyDAO { 
    self: DBProfile with BaseDao[Company] => 
    //import from DBProfile trait 
    import profile.api._ 

    class CompanyTable(tag: Tag) extends Table[Company](tag, "COMPANY") { 

    import slick.ast.BaseTypedType 
    import slick.jdbc.JdbcType 

    def name = column[String]("name") 
    def code = column[Int]("code") 

    def * = (name, code) <> (Company.tupled, Company.unapply) 
    } 

    override def toTable = TableQuery[CompanyTable] 
} 

EDIT: d'autres choses que j'ai essayé

Extension BaseDao, Si je change la déclaration de Totable à:

def toTable[S <: TableQuery[Table[_]]]():S 

L'incompatibilité de type va loin, mais je reçois maintenant :

test.scala:27: dead code following this construct [error] def findAll():Future[Seq[T]] = db.run(toTable.result)

Essayé également en utilisant un auto-type ça m'a donné la même erreur.

+0

1) https: // stackoverflow.com/questions/2224932/différence-entre-trait-héritage-et-auto-type-annotation 2) https://stackoverflow.com/questions/1990948/what-is-the-difference-between-self-types- et-trait-sous-classes 3) https://softwareengineering.stackexchange.com/questions/219038/what-is-the-difference-between-self-types-and-trait-inheritance-in-scala –

Répondre

0

If I change the declaration of toTable to:

def toTable[S <: TableQuery[Table[_]]]():S

The type mismatch goes away but I receive now:

test.scala:27: dead code following this construct [error] def findAll():Future[Seq[T]] = db.run(toTable.result) 

Any ideas why is this happening?

Je ne peux pas reproduire votre erreur de compilation spécifique.

Mais quand je change la ligne

def toTable():TableQuery[Table[T]] 

à

def toTable[S <: TableQuery[Table[_]]]():S 

J'ai erreur de compilation

Error:(24, 51) value result is not a member of Nothing 
    def findAll():Future[Seq[T]] = db.run(toTable.result) 

C'est parce que le paramètre de type S est déduit être Nothing.

Vous ne fournissez pas d'implémentation pour la méthode toTable et Nothing <: TableQuery[Table[_]].

+0

Merci pour le références, vraiment utile. Juste pour référence, j'utilise Scala 2.12.1 avec Slick 3.2.0. Ce que je ne comprends pas, c'est pourquoi toTable(): TableQuery [Table [T]] fonctionne avec les self-types et ne fonctionne pas si j'utilise l'héritage. Comment scala interprète le type de cette variable dans chaque cas, quelle est la logique? –