2016-09-01 26 views
5

Như chúng ta biết, chúng ta có thể thêm (trừ/nhân/etc) hai số khác nhau Numeric và kết quả sẽ rộng hơn trong hai loại, bất kể thứ tự của chúng.tham số kiểu và mở rộng số

33F + 9L // Float + Long == Float 
33L + 9F // Long + Float == Float 

Điều này là do mỗi người trong số 7 Numeric lớp (Byte, Short, Char, Int, Long, Float, Double) có 7 +() phương pháp khác nhau (và -(), *(), vv), một cho mỗi Numeric loại có thể nhận được dưới dạng tham số được truyền. [Có một +() phương pháp phụ để xử lý một tham số String, nhưng điều đó không nhất thiết liên quan đến chúng tôi ở đây.]

Bây giờ xem xét như sau:

implicit class PlusOrMinus[T: Numeric](a: T) { 
    import Numeric.Implicits._ 
    def +-(b: T) = if (util.Random.nextBoolean) a+b else a-b 
} 

này hoạt động nếu hai toán hạng là cùng loại, nhưng nó cũng hoạt động nếu loại toán hạng 1 rộng hơn loại thứ hai.

11F +- 2L // result: Float = 9.0 or 13.0 

Tôi tin rằng những gì đang xảy ra ở đây là trình biên dịch sử dụng weak conformance để đạt numeric widening trên các toán hạng thứ 2 (tham số b) vì nó được truyền cho phương thức +-().

Nhưng toán hạng 1 sẽ không được mở rộng để khớp với số thứ hai. Nó thậm chí sẽ không biên dịch.

11L +- 2F // Error: type mismatch; found: Float(2.0) required: Long 

Có cách nào xung quanh giới hạn này không?

Tôi không thể sử dụng thông số loại khác cho đối số b (def +-[U: Numeric](b: U) = ...) vì một Numeric, được biểu thị qua thông số loại, chỉ có thể cộng/trừ loại riêng của nó.

Là giải pháp duy nhất để tạo 7 lớp khác nhau (PlusOrMinusShort/Int/Long/, v.v.) với 7 phương pháp khác nhau (def +-(b:Short), def +-(b:Int), def +-(b:Long), v.v ...)?

Trả lời

4

Dưới đây là một cách:

implicit class PlusOrMinus[T: Numeric](a: T) { 
    import Numeric.Implicits._ 
    def +-(b: T) = plusOrMinus(a,b) 
    def +-[U: Numeric](b: U)(implicit ev: T => U) = plusOrMinus[U](a,b) 

    private def plusOrMinus[W: Numeric](a: W, b: W): W = 
    if (util.Random.nextBoolean) a+b else a-b 
} 

Sau đó, với điều này, tôi nhận được sự tương tác sau đây:

scala> 11F +- 2L 
res0: Float = 9.0 

scala> 11L +- 2F 
res1: Float = 9.0 

Ý tưởng là nếu tôi chỉ có thể có một chức năng plusOrMinus, toàn bộ vấn đề này sẽ là tầm thường, vì việc mở rộng tương tự có thể xảy ra cho một trong hai đối số. Sau khi định nghĩa một hàm như vậy, vấn đề sẽ trở thành cách nhúng nó vào một lớp ngầm định để sử dụng nó dưới dạng infix.

Ở đây, chúng tôi chỉ có hai trường hợp: đối số thứ hai cần được mở rộng hoặc đối số được bao bọc bởi lớp ẩn cần được mở rộng. Trường hợp đầu tiên trong số các trường hợp này được bao hàm bởi phương thức +- đầu tiên (vì những lý do bạn đã quan sát ở trên). Tuy nhiên, đối với lần thứ hai, chúng tôi cần phải nói rõ ràng rằng có một số chuyển đổi có thể thực hiện và chuyển loại chuyển đổi chung thành plusOrMinus.

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