2017-03-23 52 views
2

我不知道如何突破這個「無匹配的形狀找到」錯誤,除了寫很多的樣板。在Gist中說明的基本思想是,我有一個非常基本的方法版本(工作,但非常具體),然後一個版本,採用mapper參數,更通用(也可以工作,但是是特定的到一個特定的類型),然後是第三個版本,它接受一個類型參數並且非常有用,但由於這個錯誤而不能編譯。如何使通用的方法沒有得到「找不到匹配的形狀」

基本方法:

def updatePD_FirstNames(id: ids.PersonalDetailsId, firstNames: StringLtd30): Future[Int] = {

更好的方法:

def updatePD_SL(id: ids.PersonalDetailsId, mapper: tables.PersonalDetails => tables.profile.api.Rep[StringLtd30], sl: StringLtd30): Future[Int] = {

理想的方法(但不編譯):

def updatePD_X[X](id: ids.PersonalDetailsId, mapper: tables.PersonalDetails => tables.profile.api.Rep[X], sl: X): Future[Int] = {

```

[server] $ compile 
[info] Compiling 1 Scala source to ... target\scala-2.12\classes... 
[error] ...schema\DbProxy.scala:688: No matching Shape found. 
[error] Slick does not know how to map the given types. 
[error] Possible causes: T in Table[T] does not match your * projection, 
[error] you use an unsupported type in a Query (e.g. scala List), 
[error] or you forgot to import a driver api into scope. 
[error] Required level: slick.lifted.FlatShapeLevel 
[error]  Source type: slick.lifted.Rep[X] 
[error] Unpacked type: T 
[error]  Packed type: G 
[error] val q2: Query[tables.profile.api.Rep[X], X, Seq] = q1.map(mapper) 
[error]               ^
[error] one error found 
[error] (server/compile:compileIncremental) Compilation failed 
[error] Total time: 4 s, completed 23-Mar-2017 11:15:47 

```

的完整代碼在https://gist.github.com/aholland/0845bf29d836d672d006ab58f5f1c73c

回答

1

這也是理查德,換來的卻是發生在小膠質。

與第一個答案唯一的問題是,通過要求隱式BaseTypedType[X]背景下必然力的客戶端代碼的類型爲可選列提供一個隱含的BaseTypedType[Option[X]]型的,即使BaseTypedType[X]已經可用。

這是不必要的。 Slick爲你處理可選的列,如果你提供了一個隱含的BaseTypedType[X],你可以提供足夠的空間來處理Option[X]類型的列。

所以方面的約束,而它的工作原理,在無需編寫客戶端代碼,涉及直接引用null和複製已經建成油滑的邏輯implicits不是必要的,結果更加苛刻。不好。

答案是聲明隱式參數作爲長形式在其自己的參數列表中的命名爲隱式參數(以下稱爲shape),即,不使用結合速記:BaseTypedType上下文。然後,您可以指定下面使用的更復雜但要求更低的約束。

因此,解決辦法是:

def updatePD[X] (id: Long, selector: PersonTable => Rep[X], newValue: X) 
       (implicit shape: Shape[_ <: FlatShapeLevel, Rep[X], X, _]): DBIO[Int] = { 
     people.filter(_.id === id).map(selector).update(newValue) 
} 

理解爲什麼shape有確切類型Shape[_ <: FlatShapeLevel, Rep[X], X, _]取決於油滑的類型和隱性機制的深刻理解。理查德可能還寫了一篇博客文章!

2

唯一明顯的問題,我可以在你發佈的代碼看到的是,X是不受約束的。它可以是任何類型,包括Slick不知道如何處理的類型。

您可以做的是在X上添加上下文綁定。你可能想要的邊界是BaseTypedType,這是一個「鍵入類型」Slick用來識別它可以使用的類型。它是從11:30 https://www.youtube.com/watch?v=tS6N5AaZTLA

描述你會使用這樣的:

import slick.ast.BaseTypedType 

def updatePD[X : BaseTypedType](
    id: Long, 
    selector: PersonTable => Rep[X], 
    newValue: X 
): DBIO[Int] = 
    people.filter(_.id === id).map(selector).update(newValue) 

這也就意味着,當你使用的方法...

updatePD(anId, _.name, "Alice") 

...編譯器必須證明自己,無論你使用的是什麼X,Slick中都有一個合適的類型表示。

+0

非常感謝你,理查德! –

相關問題