2016-11-20 16 views
9

tôi có thể sử dụng gợi ý gỡ lỗi một tiềm ẩn:Scala: Cách nhập có thể ngăn chặn việc tìm kiếm giá trị tiềm ẩn?

Tôi muốn sử dụng ngầm, x:

type T 
trait HasT { 
    implicit def x: T = ... 
} 

Nhưng tôi cũng cần một nhập ký tự đại diện từ một số gói foo. Tôi đã thử hai cách khác nhau để giới thiệu cả hai:

class UseT extends HasT { 
    import foo._ 
    implicitly[T] // fails! "could not find implicit value" 
    // use foo stuff 
} 

class Use T { 
    object hasT extends HasT 
    import hasT.x 
    import foo._ 
    implicitly[T] // fails! "could not find implicit value" 
} 

Cả hai thất bại với "không thể tìm thấy" (không phải "giá trị impligits implicits").

Điều này xảy ra trong khi số nhận dạng ngầm x: T có thể truy cập tại điểm gọi phương thức thông qua kế thừa hoặc nhập.

Giải pháp thay thế của tôi là rebind x thành giá trị ngầm định trước khi nhập. Cả hai công việc sau đây:

implicit val x2: T = implicitly[T] 
import foo._ 
implicitly[T] // works! 

implicit val x2: T = x 
import foo._ 
implicitly[T] // works! 

giá trị gì có thể trong foo gây ra hành vi này? Lần đầu tiên tôi đoán là có một số ẩn ý cạnh tranh trong foo, nhưng nếu nó là ưu tiên cao hơn, implicitly sau đây sẽ vẫn hoạt động, và nếu nó là một ẩn ý mơ hồ, tôi sẽ nhận được một lỗi khác nhau khác nhau.

chỉnh sửa: Dự đoán của Miles là chính xác! Tôi đã tìm thấy ẩn trong bóng tối: timeColumnType. Tôi vẫn chưa hoàn toàn hiểu được quan điểm của Som Snytt rằng ẩn chứa bóng là ký tự đại diện được nhập khẩu trong khi bóng tối bị thu hút. Nhưng tôi sẽ để lại toàn bộ bài ở đây cho hậu thế:

Một đoán thứ hai, được cung cấp bởi dặm Sabin, là implicit shadowing. Tôi đã làm rõ bài viết của mình để loại trừ khả năng đó. Trường hợp đó sẽ phù hợp với lỗi của tôi nếu tôi đã thử package hasT extends HasT; import hasT._, nhưng Như som-snytt chỉ ra, hai trường hợp đó sẽ không dẫn đến bóng tối.

Trong trường hợp cụ thể của tôi, điều này có thể được xác nhận bằng cách thay đổi tên của ngầm tôi đang cố gắng sử dụng. (Tôi phải bỏ lỡ một số publishLocal hoặc reload)

Bây giờ tôi thực sự đang cố gắng sử dụng trơn. Các ngầm T trên thực sự là một ánh xạ loại cột:

import slick.driver.JdbcProfile 

class Custom { ... } // stored as `Long` in postgres 

trait ColumnTypes { 
    val profile: JdbcProfile 
    import profile.api._ // this is `foo` above 
    type T = profile.BaseColumnType[Custom] 
    implicit def customColumnType: T = 
    MappedColumnType.base[Custom, Long](_.toLong, Custom.fromLong) 
} 

class DatabaseSchema(val profile: JdbcProfile) extends ColumnTypes { 
    // `implicitly[T]` does not fail here. 
    import profile.api._ // this is also `foo` above 
    // `implicitly[T]` fails here, but it's needed for the following: 
    class CustomTable(tag: Tag) extends Table[Custom](tag, "CUSTOMS") { 
    // following fails unless I rebind customColumnType to a local implicit 
    def custom = column[Custom]("CUSTOM") 
    def * = custom 
    } 
} 

Loại api/fooJdbcProfile.API. Vi phạm tiềm ẩn có thể là here, nhưng tôi không thể biết tại sao. Tôi sẽ cố gắng ngăn chặn một số người trong số những người được nhập khẩu và xem nếu tôi có thể thu hẹp nó xuống.

+0

dụ giảm của bạn biên dịch. Nó được cho là? Tôi nhận thấy bạn đã không bí danh 'T' thành' profile.api.BaseColu ... '. Có lẽ điều đó cũng không quan trọng. –

+0

@ som-snytt Phải! Nó sẽ không biên dịch nếu ngầm định được đặt tên là 'timeColumnType'. Miles đã đúng để nghi ngờ ẩn bóng. – stewSquared

+0

Tôi đã bắt đầu đặt tên cho implicits của mình bằng đường dẫn gói đầy đủ để tránh điều này trong tương lai. – stewSquared

Trả lời

8

Tôi nghĩ rất có thể là foo chứa định nghĩa có tên x. Khi (ký tự đại diện) được nhập từ foo, nó sẽ đổ bóng định nghĩa cục bộ,

scala> object foo { val x: Boolean = true } 
defined object foo 

scala> implicit val x: Int = 23 
x: Int = 23 

scala> implicitly[Int] 
res0: Int = 23 

scala> import foo._ 
import foo._ 

scala> implicitly[Int] 
<console>:17: error: could not find implicit value for parameter e: Int 
     implicitly[Int] 
       ^
+1

Ký tự đại diện không bao giờ đổ bóng cục bộ hoặc được kế thừa hoặc nhập cụ thể. http://www.scala-lang.org/files/archive/spec/2.12/02-identifiers-names-and-scopes.html Ở đây, 'x' không rõ ràng vì nó là' import $ line.x; {import foo._; x} 'để ẩn không đủ điều kiện. –

+0

Sự thật là repl giới thiệu một phạm vi bổ sung cho lần nhập tiếp theo và thất bại 'ngầm', nhưng điều đó không có nghĩa là bóng không chịu trách nhiệm cho sự thất bại. –

+0

Hầm nói 'x' có thể truy cập được, vì vậy' f (x) 'hoạt động thay vì nhận' x là mơ hồ vì cả hai được định nghĩa và được nhập khẩu'. Đó là những gì tôi đã cố gắng để có được. Nhưng có lẽ "có thể truy cập" có nghĩa là "x không phải là tư nhân", không phải là tên được ràng buộc chính xác? –

2

Đây rõ ràng là lỗi trong tìm kiếm ngầm.

Thứ nhất, đủ điều kiện là tất cả các định x có thể được truy cập tại điểm của cuộc gọi phương pháp mà không có một tiền tố và biểu thị một ngầm định nghĩa hay một tham số ngầm. Do đó, số nhận dạng đủ điều kiện có thể là là tên địa phương hoặc thành viên của một mẫu kèm theo hoặc có thể là mà không cần tiền tố thông qua điều khoản nhập.

Trong ví dụ, không được cố định x là biểu tượng được kế thừa. X.x không thể truy cập được nếu không có tiền tố.

Tìm kiếm ngầm đang dò dẫm quá trình nhập.

$ scala 
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111). 
Type in expressions for evaluation. Or try :help. 

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

object X { def x: Int = 42 } 

trait T { def x: Int = 17 } 

object Y extends T { 
    import X._ 
    def f = x 
} 

// Exiting paste mode, now interpreting. 

defined object X 
defined trait T 
defined object Y 

scala> Y.f 
res0: Int = 17 

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

object X { implicit def x: Int = 42 } 

trait T { implicit def x: Int = 17 } 

object Y extends T { 
    import X._ 
    def f: Int = implicitly[Int] 
} 

// Exiting paste mode, now interpreting. 

<pastie>:19: error: could not find implicit value for parameter e: Int 
     def f: Int = implicitly[Int] 
           ^

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

object X { implicit def x: Int = 42 } 

trait T { implicit def x: Int = 17 } 

object Y extends T { 
    import X.{x => _, _}   // avoids bug, but is redundant 
    def f: Int = implicitly[Int] 
} 

// Exiting paste mode, now interpreting. 

defined object X 
defined trait T 
defined object Y 

scala> 

Ví dụ khác sử dụng REPL được scoped theo cách này:

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

object X { def x: Int = 42 } 
object Y { implicit def x: Int = 17 } 
object Z { 
    import Y.x 
    def f = { 
    import X._ 
    x 
    } 
} 

// Exiting paste mode, now interpreting. 

<pastie>:19: error: reference to x is ambiguous; 
it is imported twice in the same scope by 
import X._ 
and import Y.x 
      x 
     ^

đâu x không có sẵn ở tất cả, và tiềm ẩn được loại trừ một cách chính xác.

Chỉ để xác nhận:

$ scala -Xlog-implicits 
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111). 
Type in expressions for evaluation. Or try :help. 

scala> :pa 
// Entering paste mode (ctrl-D to finish) 

object X { implicit def x: Int = 42 } 

trait T { implicit def x: Int = 17 } 

object Y extends T { 
    import X._ 
    def f: Int = implicitly[Int] 
} 

// Exiting paste mode, now interpreting. 

<console>:17: x is not a valid implicit value for Int because: 
candidate implicit method x in object X is shadowed by method x in trait T 
     def f: Int = implicitly[Int] 
           ^
<console>:17: x is not a valid implicit value for Int because: 
candidate implicit method x in object X is shadowed by method x in trait T 
     def f: Int = implicitly[Int] 
           ^
<console>:17: error: could not find implicit value for parameter e: Int 
     def f: Int = implicitly[Int] 
           ^

scala> 

lẽ https://issues.scala-lang.org/browse/SI-9208

Các vấn đề liên quan