Câu trả lời:
Tôi nghĩ rằng điều này đã được hỏi, nhưng, nếu vậy, câu hỏi không rõ ràng trong thanh "liên quan". Vì vậy, đây là:
Một khung nhìn bị ràng buộc là một cơ chế được giới thiệu trong Scala để cho phép sử dụng một số loại A
như thể nó là một loại B
. Cú pháp điển hình là:
def f[A <% B](a: A) = a.bMethod
Nói cách khác, A
nên có một chuyển đổi ngầm định thành B
có sẵn, để người ta có thể gọi B
các phương thức trên một đối tượng kiểu A
. Cách sử dụng phổ biến nhất của giới hạn lượt xem trong thư viện chuẩn (trước Scala 2.8.0, dù sao), là với Ordered
, như sau:
def f[A <% Ordered[A]](a: A, b: A) = if (a < b) a else b
Bởi vì người ta có thể chuyển đổi A
thành một Ordered[A]
và vì Ordered[A]
định nghĩa phương thức <(other: A): Boolean
, tôi có thể sử dụng biểu thức a < b
.
Xin lưu ý rằng giới hạn lượt xem không được chấp nhận , bạn nên tránh chúng.
Giới hạn ngữ cảnh được giới thiệu trong Scala 2.8.0 và thường được sử dụng với mẫu lớp được gọi là kiểu mẫu , một mẫu mã mô phỏng chức năng được cung cấp bởi các lớp loại Haskell, mặc dù theo cách thức dài dòng hơn.
Mặc dù chế độ xem bị ràng buộc có thể được sử dụng với các loại đơn giản (ví dụ A <% String
:), một bối cảnh bị ràng buộc yêu cầu một loại tham số hóa , chẳng hạn như Ordered[A]
ở trên, nhưng không giống như String
.
Một bối cảnh bị ràng buộc mô tả một giá trị ngầm định , thay vì xem chuyển đổi ngầm định của ràng buộc . Nó được sử dụng để tuyên bố rằng đối với một số loại A
, có một giá trị ngầm định của loại B[A]
có sẵn. Cú pháp như sau:
def f[A : B](a: A) = g(a) // where g requires an implicit value of type B[A]
Điều này gây nhầm lẫn hơn so với chế độ xem bị ràng buộc bởi vì nó không rõ ràng ngay lập tức làm thế nào để sử dụng nó. Ví dụ phổ biến về việc sử dụng trong Scala là:
def f[A : ClassManifest](n: Int) = new Array[A](n)
Một Array
khởi tạo trên một kiểu tham số hóa đòi hỏi ClassManifest
phải có sẵn, vì những lý do phức tạp liên quan đến việc xóa kiểu và bản chất không xóa của mảng.
Một ví dụ rất phổ biến khác trong thư viện phức tạp hơn một chút:
def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
Ở đây, implicitly
được sử dụng để truy xuất giá trị ngầm định mà chúng ta muốn, một kiểu Ordering[A]
, lớp nào định nghĩa phương thức compare(a: A, b: A): Int
.
Chúng ta sẽ thấy một cách khác để làm điều này dưới đây.
Không có gì đáng ngạc nhiên khi cả giới hạn xem và giới hạn bối cảnh được triển khai với các tham số ngầm định, được đưa ra định nghĩa của chúng. Trên thực tế, cú pháp tôi chỉ ra là đường cú pháp cho những gì thực sự xảy ra. Xem bên dưới cách họ khử đường:
def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod
def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)
Vì vậy, một cách tự nhiên, người ta có thể viết chúng theo cú pháp đầy đủ của chúng, đặc biệt hữu ích cho giới hạn ngữ cảnh:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)
Giới hạn lượt xem được sử dụng chủ yếu để tận dụng mô hình thư viện của tôi , thông qua đó một phương thức "thêm" vào một lớp hiện có, trong trường hợp bạn muốn trả về kiểu ban đầu bằng cách nào đó. Nếu bạn không cần phải trả về loại đó theo bất kỳ cách nào, thì bạn không cần một chế độ xem bị ràng buộc.
Ví dụ cổ điển về việc sử dụng ràng buộc xem là xử lý Ordered
. Lưu ý rằng Int
không phải là Ordered
, ví dụ, mặc dù có một chuyển đổi ngầm. Ví dụ được đưa ra trước đây cần một khung nhìn bị ràng buộc bởi vì nó trả về kiểu không được chuyển đổi:
def f[A <% Ordered[A]](a: A, b: A): A = if (a < b) a else b
Ví dụ này sẽ không hoạt động mà không có giới hạn xem. Tuy nhiên, nếu tôi phải trả về loại khác, thì tôi không cần phải xem chế độ xem nữa:
def f[A](a: Ordered[A], b: A): Boolean = a < b
Việc chuyển đổi ở đây (nếu cần) xảy ra trước khi tôi chuyển tham số cho f
, vì vậy f
không cần biết về nó.
Ngoài ra Ordered
, cách sử dụng phổ biến nhất từ thư viện là xử lý String
và Array
, đó là các lớp Java, giống như chúng là các bộ sưu tập Scala. Ví dụ:
def f[CC <% Traversable[_]](a: CC, b: CC): CC = if (a.size < b.size) a else b
Nếu một người cố gắng làm điều này mà không có giới hạn lượt xem, kiểu trả về của a String
sẽ là WrappedString
(Scala 2.8) và tương tự cho Array
.
Điều tương tự xảy ra ngay cả khi loại chỉ được sử dụng làm tham số loại của loại trả về:
def f[A <% Ordered[A]](xs: A*): Seq[A] = xs.toSeq.sorted
Giới hạn bối cảnh chủ yếu được sử dụng trong cái được gọi là mẫu typeclass , như một tham chiếu đến các lớp loại của Haskell. Về cơ bản, mẫu này thực hiện thay thế cho kế thừa bằng cách cung cấp chức năng thông qua một loại mẫu bộ điều hợp ngầm.
Ví dụ kinh điển là Scala 2.8 Ordering
, thay thế Ordered
trong thư viện của Scala. Cách sử dụng là:
def f[A : Ordering](a: A, b: A) = if (implicitly[Ordering[A]].lt(a, b)) a else b
Mặc dù bạn sẽ thường thấy rằng được viết như thế này:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = {
import ord.mkOrderingOps
if (a < b) a else b
}
Việc tận dụng một số chuyển đổi ngầm bên trong Ordering
cho phép kiểu toán tử truyền thống. Một ví dụ khác trong Scala 2.8 là Numeric
:
def f[A : Numeric](a: A, b: A) = implicitly[Numeric[A]].plus(a, b)
Một ví dụ phức tạp hơn là việc sử dụng bộ sưu tập mới CanBuildFrom
, nhưng đã có một câu trả lời rất dài về điều đó, vì vậy tôi sẽ tránh nó ở đây. Và, như đã đề cập trước đây, có ClassManifest
cách sử dụng, được yêu cầu để khởi tạo các mảng mới mà không cần các loại cụ thể.
Bối cảnh bị ràng buộc với mẫu kiểu chữ có nhiều khả năng được sử dụng bởi các lớp của chính bạn, vì chúng cho phép phân tách các mối quan tâm, trong khi các giới hạn có thể tránh được trong mã của bạn bằng thiết kế tốt (nó được sử dụng chủ yếu để đi xung quanh thiết kế của người khác ).
Mặc dù điều đó đã có thể trong một thời gian dài, việc sử dụng các giới hạn bối cảnh đã thực sự phát huy trong năm 2010, và hiện được tìm thấy ở một mức độ nào đó trong hầu hết các thư viện và khung quan trọng nhất của Scala. Tuy nhiên, ví dụ cực đoan nhất về cách sử dụng của nó là thư viện Scalaz, nơi mang lại rất nhiều sức mạnh của Haskell cho Scala. Tôi khuyên bạn nên đọc lên các mẫu typeclass để làm quen với tất cả các cách mà nó có thể được sử dụng.
BIÊN TẬP
Các câu hỏi liên quan: