Tôi muốn triển khai một lớp C
để lưu trữ các giá trị của các loại số khác nhau, cũng như boolean. Hơn nữa, tôi muốn có thể hoạt động trên các trường hợp của lớp này, giữa các loại, chuyển đổi khi cần thiết Int --> Double
và Boolean -> Int
, tức là, để có thể thêm Boolean + Boolean
, Int + Boolean
, Boolean + Int
, Int + Double
, Double + Double
v.v. nhập (Int
hoặc Double
) bất cứ khi nào có thể.Cách thiết lập chuyển đổi ngầm để cho phép số học giữa các loại số?
Cho đến nay tôi đến với điều này:
abstract class SemiGroup[A] { def add(x:A, y:A):A }
class C[A] (val n:A) (implicit val s:SemiGroup[A]) {
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
}
object Test extends Application {
implicit object IntSemiGroup extends SemiGroup[Int] {
def add(x: Int, y: Int):Int = x + y
}
implicit object DoubleSemiGroup extends SemiGroup[Double] {
def add(x: Double, y: Double):Double = x + y
}
implicit object BooleanSemiGroup extends SemiGroup[Boolean] {
def add(x: Boolean, y: Boolean):Boolean = true;
}
implicit def bool2int(b:Boolean):Int = if(b) 1 else 0
val n = new C[Int](10)
val d = new C[Double](10.5)
val b = new C[Boolean](true)
println(d + n) // [1]
println(n + n) // [2]
println(n + b) // [3]
// println(n + d) [4] XXX - no implicit conversion of Double to Int exists
// println(b + n) [5] XXX - no implicit conversion of Int to Boolean exists
}
này làm việc cho một số trường hợp (1, 2, 3) nhưng không cho (4, 5). Lý do là có sự mở rộng tiềm ẩn của loại từ thấp hơn đến cao hơn, nhưng không phải là cách khác. Nói cách khác, phương pháp
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
bằng cách nào đó cần phải có một phương pháp đối tác đó sẽ giống như thế:
def +[T, A <% T](that:C[T]):T = that.s.add(this.n, that.n)
nhưng điều đó không biên dịch vì hai lý do, trước hết là trình biên dịch không thể chuyển đổi this.n
để nhập T
(mặc dù chúng tôi chỉ định chế độ xem bị ràng buộc A <% T
) và thứ hai, ngay cả khi nó có thể chuyển đổi this.n
, sau khi xóa hai phương thức +
trở nên mơ hồ.
Rất tiếc, quá trình này quá dài. Bất kì sự trợ giúp nào đều được đánh giá cao! Nếu không có vẻ như tôi phải viết ra tất cả các hoạt động giữa tất cả các loại một cách rõ ràng. Và nó sẽ nhận được lông nếu tôi đã phải thêm các loại bổ sung (Complex
là tiếp theo trên menu ...).
Có thể ai đó có cách khác để đạt được tất cả điều này hoàn toàn? Cảm thấy như có một cái gì đó đơn giản tôi nhìn ra.
Cảm ơn trước!
AHHA! Tôi thấy cách này hoạt động - cảm ơn bạn! Việc thêm một 'Boolean' hóa ra là dễ dàng, thực sự, và LUB của' Numeric' sẽ không quá khó để thay đổi cho 'Phức tạp'. Tôi tò mò - dường như bạn đã có giải pháp này tiện dụng lên tay áo của bạn, trong bối cảnh bạn đã gặp phải vấn đề này? Ngoài ra tôi đã cố gắng để kiểm tra hiệu suất của giải pháp này và tổng hợp một triệu 'C [Int]' 's dường như là khoảng năm lần chậm hơn so với một triệu 'Int' của ... Bất kỳ suy nghĩ về cách bắt đầu tối ưu hóa điều này? – ostolop
Tôi chơi xung quanh điều này trong một cuộc thảo luận với @extempore trên IRC, nó không giải quyết được một vấn đề cụ thể của tôi. 5x chi phí không âm thanh quá xấu xem xét các indirection. Bạn có thể gọi trực tiếp 'wc.a2b' và' wc.a2c' thay vì sử dụng phương thức 'unify'. Hiện tại, các đầu vào và đầu ra của 'NumeriC# plus' được đóng hộp, hy vọng một phiên bản tương lai của Scala sẽ tìm cách để @specialize vấn đề đó đi. – retronym
@retronym Thực ra ... Tôi đã bắt đầu cuộc thảo luận đó. :-) –