Nếu bạn chỉ muốn sử dụng thư viện chuẩn scala, hãy xem Numeric[T]
. Trong trường hợp của bạn, vì bạn muốn làm một bộ phận không phải số nguyên, bạn sẽ phải sử dụng lớp con Fractional[T]
của Numeric
.
Dưới đây là cách mã sẽ xem xét bằng cách sử dụng thư viện chuẩn scala chuẩn. Lưu ý rằng Fractional
kéo dài từ Ordered
. Điều này thuận tiện trong trường hợp này, nhưng nó cũng không phải là toán học chung chung. Ví dụ. bạn không thể xác định Fractional[T]
cho Complex
vì nó không được đặt hàng.
def bucketiseScala[T: Fractional](buckets: Seq[T], candidate: T): T = {
// so we can use integral operators such as + and/
import Fractional.Implicits._
// so we can use ordering operators such as <. We do have a Ordering[T]
// typeclass instance because Fractional extends Ordered
import Ordering.Implicits._
// integral does not provide a simple way to create an integral from an
// integer, so this ugly hack
val two = (implicitly[Fractional[T]].one + implicitly[Fractional[T]].one)
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/two
if (candidate < midPoint) x else y
}
}
Tuy nhiên, để tính toán số học chung chung tôi khuyên bạn nên xem spire. Nó cung cấp một hệ thống phân cấp phức tạp hơn nhiều về typeclasses số. Spire typeclasses cũng là chuyên ngành và do đó thường nhanh như làm việc trực tiếp với nguyên thủy.
Dưới đây là làm thế nào để sử dụng ví dụ sẽ tìm bằng chóp:
// imports all operator syntax as well as standard typeclass instances
import spire.implicits._
// we need to provide Order explicitly, since not all fields have an order.
// E.g. you can define a Field[Complex] even though complex numbers do not
// have an order.
def bucketiseSpire[T: Field: Order](buckets: Seq[T], candidate: T): T = {
// spire provides a way to get the typeclass instance using the type
// (standard practice in all libraries that use typeclasses extensively)
// the line below is equivalent to implicitly[Field[T]].fromInt(2)
// it also provides a simple way to convert from an integer
// operators are all enabled using the spire.implicits._ import
val two = Field[T].fromInt(2)
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/two
if (candidate < midPoint) x else y
}
}
Spire thậm chí cung cấp chuyển đổi tự động từ các số nguyên để T
nếu tồn tại một Field[T]
, vì vậy bạn thậm chí có thể viết ví dụ như thế này (gần giống như phiên bản không chung chung). Tuy nhiên, tôi nghĩ ví dụ trên dễ hiểu hơn.
// this is how it would look when using all advanced features of spire
def bucketiseSpireShort[T: Field: Order](buckets: Seq[T], candidate: T): T = {
buckets.foldLeft(buckets.head) { (x, y) =>
val midPoint = (x + y)/2
if (candidate < midPoint) x else y
}
}
Cập nhật: chóp rất mạnh mẽ và chung chung, nhưng cũng có thể hơi khó hiểu đối với người mới bắt đầu. Đặc biệt là khi mọi thứ không hoạt động. Đây là một số excellent blog post giải thích cách tiếp cận cơ bản và một số vấn đề.
OK, tôi sẽ kiểm tra chóp. Vấn đề là các tài liệu scala cho Int (http://www.scala-lang.org/api/current/index.html#scala.Int) không liệt kê các đặc điểm mà nó mở rộng để tôi kết thúc việc đoán về '. Làm thế nào tôi có thể tìm ra những đặc điểm 'Int' mở rộng để tôi có thể tìm thấy' Numeric [T] 'cho bản thân mình? – jbrown
@jbrown Đặt hàng là [typeclass] (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html). Typeclasses không hoạt động khi sử dụng thừa kế. –
Vậy làm thế nào có thể biết được, bằng cách xem các tài liệu, mà typeclasses áp dụng cho Int? – jbrown