2015-12-07 16 views
6

Tôi khá mới đối với Scala và đã cố gắng tìm hiểu và hiểu các chuyển đổi và tham số tiềm ẩn và đã gặp phải một kịch bản mà tôi thấy khó hiểu.Tham số hàm khởi tạo lớp trừu tượng và kế thừa trong Scala

Đối với ngữ cảnh, tôi đang sử dụng Scaldi để thực hiện tiêm phụ thuộc trong ứng dụng Akka và muốn có nhiều tác nhân được tiêm kế thừa từ lớp trừu tượng. Tôi tin rằng tôi không thể làm cho lớp trừu tượng trở thành một đặc điểm chính xác bởi vì chúng ta cần tạo ra một đối tượng ngụ ý Injector có sẵn thông qua một đối số hàm tạo để tận dụng khung công tác.

Một ví dụ rất giả tạo đó thể hiện những hành vi mà tôi đang nhìn thấy là như sau:

class SecretSauce {} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

class Concrete extends Base {} 

object Example extends App { 
    ... // Setup Actor system, etc, etc 
    implicit val secretSauce: SecretSauce = new SecretSauce() 
} 

Tôi đã chờ đợi điều cần làm việc nhưng thay vào đó tôi nhận được một lỗi biên dịch:

Unspecified value parameter secretSauce. 
class Concrete extends Base { 
      ^

Nếu tôi thêm tham số ngầm vào lớp bê tông, như vậy, mọi thứ hoạt động:

class Concrete(implicit secretSauce: SecretSauce) extends Base {} 

I t hink nhầm lẫn của tôi bắt nguồn từ các tham số ngầm định hoạt động như thế nào - trong các tình huống như mô tả tôi đang mô tả, chúng không được thừa hưởng bởi các lớp con? Ai đó có thể ELI5 những gì đang xảy ra trong ví dụ của tôi hoặc chỉ cho tôi một tham chiếu có thể giúp mọi thứ rõ ràng?

Cảm ơn!

Trả lời

2

Các quy tắc chính xác mà xác định nơi trình biên dịch Scala tìm kiếm implicits là loại phức tạp, nhưng trong hầu hết các tình huống bạn chỉ cần phải suy nghĩ về hai nơi các giá trị tiềm ẩn có thể đến từ:

  1. Phạm vi hiện tại.
  2. Các đối tượng đồng hành cho mọi loại có liên quan.

Điều này có nghĩa này sẽ biên dịch:

class SecretSauce {} 

object SecretSauce { 
    implicit val secretSauce: SecretSauce = new SecretSauce() 
} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

object Example extends App { 
    class Concrete extends Base {} 
} 

Hoặc này:

class SecretSauce {} 

abstract class Base(implicit secretSauce: SecretSauce) {} 

object Example extends App { 
    implicit val secretSauce: SecretSauce = new SecretSauce() 

    class Concrete extends Base {} 
} 

Trong phiên bản của bạn, tuy nhiên, khi trình biên dịch được đến dòng này:

class Concrete extends Base {} 

Nó sẽ biết rằng nó cần phải tìm một ẩn SecretSauce va lue, và nó sẽ xem xét đầu tiên tại các giá trị tiềm ẩn trong phạm vi tại dòng đó và tiếp theo trong đối tượng đồng hành SecretSauce (nếu nó tồn tại). Nó không tìm thấy một trong hai, do đó, nó từ chối biên dịch mã của bạn.

+0

Ahh, tôi nghĩ rằng việc chưng cất các quy tắc sẽ giúp khá nhiều. Tại sao một lỗi biên dịch không được ném trong trường hợp đối số ngầm được nhân đôi trong lớp bê tông? ví dụ: lớp bê tông (bí mật ngầmSauce: SecretSauce) mở rộng Base {} ' Từ cách tôi đã thiết lập nó trong mã của tôi, giá trị tiềm ẩn vẫn không nằm trong phạm vi cũng không nằm trong đối tượng đồng hành, phải không? Tôi có hiểu biết về phạm vi ở đây không? – simonl

+0

@simonl Khi bạn thêm tham số ngầm vào hàm tạo 'Concrete', hàm ẩn sẽ nằm trong phạm vi cho lệnh gọi hàm khởi tạo của hàm cha. Cú pháp của Scala đối với các định nghĩa lớp và các hàm xây dựng làm cho điều này không rõ ràng một chút, nhưng nó hoạt động. –

1

Các tham số ngầm được "giải quyết" từ:

  • Implicits được xác định trong phạm vi hiện tại
  • Explicit nhập khẩu
  • Wildcard nhập khẩu

Để xác định class Concrete như xa như tôi hiểu , tiềm ẩn cần được xác định hoặc được nhập.

Tôi tìm thấy giải thích rất tốt trong this SO answer.

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