2010-12-31 36 views
14

Tôi viếtChuyển đổi ngầm định, có cần nhập hay không?

object MyString { 
    implicit def stringToMyString(s: String) = new MyString(s)  
} 

class MyString(str: String) { 
    def camelize = str.split("_").map(_.capitalize).mkString 

    override def toString = str 
} 


object Parse { 
    def main(args: Array[String]) { 
    val x = "active_record".camelize 
    // ... 
    } 
} 

trong chương trình của mình. Điều này gây ra lỗi biên dịch. Sau khi tôi chèn

import MyString.stringToMyString 

Sau đó, nó hoạt động.

Từ Odersky's Lập trình trong Scala Tôi nhận được chuyển đổi ngầm định trong đối tượng đồng hành của nguồn hoặc các loại mục tiêu dự kiến ​​không cần phải nhập.

Trả lời

16

chuyển đổi ẩn trong đối tượng đồng hành của nguồn hoặc mong đợi loại mục tiêu không cần phải làĐã nhập.

Đủ rồi. Bây giờ, phương thức camelize được định nghĩa trên lớp MyString và thực sự, có một chuyển đổi tiềm ẩn thành MyString bên trong đối tượng đồng hành của nó. Tuy nhiên, không có gì trong mã cho trình biên dịch biết rằng MyString là loại mục tiêu được mong đợi là.

Nếu, thay vào đó, bạn là người viết:

val x = ("active_record": MyString).camelize 

sau đó nó sẽ làm việc, bởi vì trình biên dịch sẽ biết bạn mong đợi"active_record" là một MyString, làm cho nó trông lên chuyển đổi ngầm bên trong đối tượng MyString.

Điều này có thể hơi hạn chế, nhưng nó thực sự hoạt động ở một số địa điểm.Say, ví dụ, bạn có:

class Fraction(num: Int, denom: Int) { 
    ... 
    def +(b: Fraction) = ... 
    ... 
} 

Và sau đó bạn đã có một mã như thế này:

val x: Fraction = ... 
val y = x + 5 

Bây giờ, x không có một phương pháp +, mà dự kiến ​​loạiFraction. Vì vậy, trình biên dịch sẽ xem xét, ở đây, cho một chuyển đổi tiềm ẩn từ Int thành Fraction bên trong đối tượng Fraction (và bên trong đối tượng Int, nếu có, vì đó là loại nguồn).

13

Trong trường hợp này, bạn cần nhập vì trình biên dịch không biết bạn đã rút phương thức camelize từ đâu. Nếu loại là rõ ràng, nó sẽ biên dịch mà không cần nhập khẩu:

object Parse { 
    def foo(s: MyString) = s.camelize 

    def main(args: Array[String]) { 
    val x = foo("active_record") 
    println(x.toString) 
    } 
} 

Xem Pimp my library pattern, dựa trên Martin's article:

Lưu ý rằng nó không thể đưa defs ở cấp cao nhất, vì vậy bạn có thể' t xác định một chuyển đổi tiềm ẩn với phạm vi toàn cầu. Giải pháp là để đặt các def bên trong một đối tượng, và sau đó nhập nó, tức là

object Implicits { 
    implicit def listExtensions[A](xs : List[A]) = new ListExtensions(xs) 
} 

Và sau đó ở phía trên cùng của mỗi tập tin nguồn, cùng với hàng nhập khẩu khác của bạn:

import Implicits._ 
+1

IIRC bạn có thể đặt việc nhập vào đối tượng gói, làm cho ít nhất một chút "toàn cầu" :-) – Landei

0

Tôi đã thử các lớp dụ Rational trong Lập trình trong Scala cuốn sách, đặt một phương pháp tiềm ẩn trong đối tượng đồng hành của nó:

object Rational { 
    implicit def intToRational(num: Int) = 
    new Rational(num) 
} 

nhưng mã

2 + new Rational(1, 2) 

không hoạt động. Để chuyển đổi xảy ra, quy tắc mã định danh duy nhất được áp dụng, tức là bạn cần phải nhập phương thức tường minh vào phạm vi ngay cả khi được xác định trong đối tượng đồng hành.

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