2009-08-27 31 views
15

tôi đang cố gắng để tạo ra một chuyển đổi ngầm từ bất kỳ loại (nói, Int) vào một String ...Tránh ngầm def nhập nhằng trong Scala

Một chuyển đổi ngầm để String là các phương thức RichString (như ngược lại) không có sẵn .

implicit def intToString(i: Int) = String.valueOf(i) 
100.toCharArray // => Array[Char] = Array(1, 0, 0) 
100.reverse // => error: value reverse is not a member of Int 
100.length // => 3 

Một chuyển đổi ngầm để RichString nghĩa phương pháp String (như toCharArray) không có sẵn

implicit def intToRichString(i: Int) = new RichString(String.valueOf(i)) 
100.reverse // => "001" 
100.toCharArray // => error: value toCharArray is not a member of Int 
100.length // => 3 

Sử dụng cả hai chuyển đổi tiềm ẩn là các phương thức trùng lặp (như chiều dài) là mơ hồ.

implicit def intToString(i: Int) = String.valueOf(i) 
implicit def intToRichString(i: Int) = new RichString(String.valueOf(i)) 
100.toCharArray // => Array[Char] = Array(1, 0, 0) 
100.reverse // => "001" 
100.length // => both method intToString in object $iw of type 
    // (Int)java.lang.String and method intToRichString in object 
    // $iw of type (Int)scala.runtime.RichString are possible 
    // conversion functions from Int to ?{val length: ?} 

Vì vậy, có thể chuyển đổi hoàn toàn thành chuỗi và vẫn hỗ trợ tất cả các phương thức String và RichString không?

Trả lời

2

Hoặc tạo ra một lớp proxy khổng lồ, hoặc hút nó lên và yêu cầu khách hàng để disambiguate nó:

100.asInstanceOf [Chuỗi] .length

+0

Có vẻ như 'hút nó lên' là lựa chọn tốt nhất. Thiết kế API trong Scala là khó khăn hơn đáng kể so với việc là một người tiêu dùng API. Tôi muốn tạo một kiểu dữ liệu bao bọc một giá trị và cho phép người dùng API xử lý kiểu dữ liệu như thể nó là kiểu giá trị tập trung. Ví dụ. nếu nó kết thúc tốt đẹp một Int, sau đó đối xử với đối tượng như một int. Hóa ra điều này là quá khó. tôi đang xem xét đưa ra phương pháp datatype helper của tôi: loại T val internedValue: T def s = internedValue.asInstanceOf [Chuỗi] def i = internedValue.asInstanceOf [Int] ... vv – Synesso

+20

thích '(100: String) .length', vì đây là kiểu an toàn, trong khi 'asInstanceOf' thì không. Bên cạnh đó, nó đẹp hơn và ngắn hơn. –

+2

Không chỉ vậy, nhưng asInstanceOf sẽ không bao giờ làm việc ở đây, vì nó chỉ bao giờ downcasting (mà là ràng buộc để thất bại ở đây) và sẽ không bắt đầu bất kỳ chuyển đổi tiềm ẩn. Nói cách khác '100.asInstanceOf [String] .length' sẽ luôn thất bại với' ClassCastException' –

2

Tùy chọn duy nhất tôi thấy là tạo một lớp Trình bao bọc chuỗi mới MyString và cho phép gọi bất kỳ phương thức nào bạn muốn được gọi trong trường hợp không rõ ràng. Sau đó, bạn có thể xác định chuyển đổi tiềm ẩn cho MyString và hai chuyển đổi tiềm ẩn từ MyString thành String và RichString, chỉ trong trường hợp bạn cần chuyển nó sang hàm thư viện.

+0

Điều này nghe có vẻ giống như một cách tiếp cận công bằng, nhưng rất nhiều công việc. Plus Tôi nghi ngờ nó không phải là bằng chứng trong tương lai, như chuyển đổi tiềm ẩn khác được giới thiệu. – Synesso

+0

Chắc chắn nó là rất nhiều công việc, nhưng không phải là rất nhiều suy nghĩ, chỉ cần gõ. ;) Và tại sao nó không phải là bằng chứng trong tương lai? Không ai buộc bạn sử dụng bất kỳ chuyển đổi tiềm ẩn nào có thể được giới thiệu trong tương lai, thậm chí không phải những chuyển đổi trong quá trình tải trước. –

+0

@Kim Stebel: 'Chắc chắn nó là rất nhiều công việc, nhưng không phải là rất nhiều suy nghĩ, chỉ cần gõ' lập trình là những người suy nghĩ lười biếng, không làm việc chăm chỉ. –

1

Tôi đang bối rối: bạn không thể sử dụng .toString trên bất kỳ loại nào, do đó, tránh nhu cầu chuyển đổi tiềm ẩn?

+0

Tôi không nghĩ rằng sẽ thay đổi vấn đề, ngoại trừ có lẽ giới thiệu ngoại lệ con trỏ null. Để rõ ràng, bạn đang đề xuất thay đổi String.valueOf (i) thành i.toString? – Synesso

5

Tôi không có một giải pháp, nhưng sẽ bình luận rằng lý do các phương pháp RichString không có sẵn sau khi intToString ẩn ý của bạn là Scala không thực hiện các cuộc gọi ngầm định (xem 21.2 "Quy tắc về implicits" trong Lập trình trong Scala).

Nếu bạn giới thiệu một số trung gian String, Scala sẽ làm cho hội tụ ngụ ý thành một RichString (ngầm định được xác định trong Predef.scala).

Ví dụ:

$ scala 
Welcome to Scala version 2.7.5.final [...]. 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> implicit def intToString(i: Int) = String.valueOf(i) 
intToString: (Int)java.lang.String 

scala> val i = 100 
i: Int = 100 

scala> val s: String = i 
s: String = 100 

scala> s.reverse 
res1: scala.runtime.RichString = 001 
+0

Điều đó là tốt để biết! Cảm ơn bạn. – Synesso

+0

Đây có phải là "chỉ" một nhược điểm của việc cho phép các mối quan hệ chuyển đổi tiềm ẩn vòng tròn, hoặc có các lý do khác không? Vì ngay cả khi bạn có một vòng tròn, bạn sẽ tĩnh có thể tìm thấy việc triển khai "gần nhất". Khám phá một biểu đồ mà không cần truy cập đồ thị hai lần không phải là khó, mặc dù nó có thể mất một lúc. – Raphael

5

Tính đến Scala 2.8, điều này đã được cải thiện. Theo this paperTránh sự mơ hồ):

Trước đây, fi Speci nhất c phương pháp quá tải hoặc ngầm chuyển đổi sẽ được lựa chọn dựa trên các loại lý luận của phương pháp. Có một điều khoản bổ sung là cho biết rằng phương pháp cụ thể nhất không thể là được xác định trong một siêu lớp thích hợp của bất kỳ lựa chọn thay thế nào khác. Phương án này đã được thay thế bằng Scala 2.8 theo cách sau, tự do hơn: Khi so sánh hai phương án áp dụng khác nhau của phương pháp quá tải hoặc ngầm định, mỗi phương pháp sẽ có một điểm để có nhiều đối số cụ thể hơn, và một điểm khác cho được xác định trong một lớp con thích hợp . Một "chiến thắng" thay thế cho người khác nếu nó nhận được số lượng lớn hơn của hai điểm so sánh này.Điều này có nghĩa là nếu lựa chọn thay thế có các loại đối số giống nhau, loại được xác định trong một lớp con thắng .

Xem that other paper (§6.5) để biết ví dụ.

+0

Liên kết của bạn tới trang đầu tiên bị hỏng. –

2

Giải pháp được chấp nhận (được đăng bởi Mitch Blevins) sẽ không bao giờ hoạt động: downcasting Int đến String sử dụng asInstanceOf sẽ luôn thất bại.

Một giải pháp cho vấn đề của bạn là thêm một sự chuyển đổi từ bất kỳ String-mui trần kiểu để RichString (hay đúng hơn, để StringOps như bây giờ được đặt tên):

implicit def stringLikeToRichString[T](x: T)(implicit conv: T => String) = new collection.immutable.StringOps(conv(x)) 

Sau đó, xác định chuyển đổi của bạn (s) để chuỗi như trước:

scala> implicit def intToString(i: Int) = String.valueOf(i) 
warning: there was one feature warning; re-run with -feature for details 
intToString: (i: Int)String 

scala> 100.toCharArray 
res0: Array[Char] = Array(1, 0, 0) 

scala> 100.reverse 
res1: String = 001 

scala> 100.length 
res2: Int = 3 
Các vấn đề liên quan