2013-02-18 34 views
8

Tôi có trường hợp sử dụng sau đó xảy ra thường xuyên trong mã của tôi:Làm thế nào để chuyển đổi một danh sách [A] vào một danh sách [B] sử dụng một chuyển đổi ngầm

  • Một Collection [A]
  • Một ngầm chuyển đổi A đến B

và tôi muốn để có được một bộ sưu tập của B. tôi có thể sử dụng ngầm như sau:

case class Items(underlying:List[B]) 
    import B._ 
    def apply(a:List[A]):Items = { 
    val listOfB= a.map {implicitly[A=>B]} 
    Items(listOfB) 
    } 

Cách thanh lịch nhất để làm điều đó trong Scala, có lẽ với sự giúp đỡ của Scalaz làm như vậy?

Chỉnh sửa: mục tiêu của câu hỏi của tôi là tìm cách thức thành ngữ, một cách tiếp cận chung giữa các thư viện/nhà phát triển. Trong ý nghĩa đó, việc phát triển giải pháp pimp-my-library của riêng tôi là điều tôi không thích, bởi vì những người khác viết mã của tôi sẽ không biết sự tồn tại của chuyển đổi này và sẽ không sử dụng nó, và họ sẽ tự viết lại. Tôi ủng hộ bằng cách sử dụng một phương pháp thư viện cho các chức năng phổ biến này và đó là lý do tại sao tôi tự hỏi liệu trong Scalaz nó tồn tại một tính năng như vậy.

Trả lời

14

Khá đơn giản nếu bạn biết các loại. chuyển đổi ngầm đầu tiên A-B:

implicit def conversion(a: A): B = //... 

sau đó bạn cần chuyển đổi ngầm List[S]-List[T] nơi ST nhiều loại tùy ý mà ngầm chuyển đổi S-T tồn tại:

implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] = 
    input map c 

này nên sau đó làm việc:

val listOfA: List[A] = //... 
val listOfB: List[B] = listOfA 

đó đã được giải quyết bởi trình biên dịch để:

val listOfB: List[B] = convList(listOfA)(conversion) 

nơi SATB.

+0

Có phải đó là một phần của một số thư viện chuẩn không? Tôi ghét phát minh lại bánh xe – Edmondo1984

+0

@ Edmondo1984: không biết, tôi đã viết nó từ đầu ngay bây giờ, nhưng tôi có thể được tái phát minh bánh xe là tốt. BTW đọc câu trả lời của tôi một lần nữa, tôi đã mở rộng giải pháp, do đó bạn chỉ cần một chuyển đổi ngầm định 'convList' cho bất kỳ loại chuyển đổi nào. –

9

tôi sẽ không sử dụng một chuyển đổi ngầm ở đây, nhưng một cái nhìn bị ràng buộc trong lớp:

case class Foo(x: Int) 
case class Bar(y: Int) 
implicit def foo2Bar(foo: Foo) = Bar(foo.x) 
case class Items[A <% Bar](xs: List[A]) { 
    def apply(x: Int): Bar = xs(x) 
} 

Bây giờ bạn có thể tạo một thể hiện của Items với một danh sách các Foo và trong nội bộ sử dụng chúng, như thể họ là Bar s.

scala> Items(List(Foo(1))) 
res8: Items[Foo] = Items(List(Foo(1))) 

scala> res8(0) 
res9: Bar = Bar(1) 

chỉnh sửa:

Một số làm rõ, tại sao tôi sẽ không sử dụng một chuyển đổi ngầm:

chuyển đổi ngầm có thể nguy hiểm, khi họ đang ở trong phạm vi và vô tình chuyển đổi mọi thứ, rằng họ không nên chuyển đổi. Tôi sẽ luôn luôn chuyển đổi nội dung một cách rõ ràng hoặc thông qua giới hạn xem, bởi vì sau đó tôi có thể kiểm soát nó, cũng chuyển đổi tiềm ẩn có thể thu nhỏ kích thước mã của bạn, nhưng cũng khiến người khác khó hiểu hơn. Tôi sẽ chỉ sử dụng chuyển đổi ngầm cho mẫu 'mở rộng thư viện của tôi'.

edit2:

Bạn tuy nhiên có thể thêm một phương pháp để các loại bộ sưu tập, mà không chuyển đổi này, nếu một phương pháp như vậy là trong phạm vi:

trait Convertable[M[A], A] { 
    def convertTo[B](implicit f: A => B): M[B] 
} 

implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] { 
    def convertTo[B](implicit f: A => B) = xs.map(f) 
} 

scala> implicit def int2String(x: Int) = x.toString 
int2String: (x: Int)String 

scala> List(1,2,3).convertTo[String] 
res0: List[String] = List(1, 2, 3) 

Thay vì sử dụng một chuyển đổi ngầm ở đây , Tôi có lẽ sẽ sử dụng một typeclass thay vào đó, nhưng tôi nghĩ rằng bạn có được ý tưởng cơ bản.

1

trình bắt đầu với Scala 2.10:

implicit class ListOf[A](val list: List[A]) { 
    def of[B](implicit f: A => B): List[B] = list map f 
} 
implicit def int2String(i: Int) = i.toString 

// Usage 
List(1,2,3).of[String] 
+0

Điều này chỉ hoạt động trong scala 2.10 – mericano1

+0

Có, nó đã được ra – idonnie

+0

Tôi biết, tôi đã chỉ chỉ ra nó sẽ có lợi để xác định rằng trong câu trả lời – mericano1

-1

Trong mã của tôi, tôi đang sử dụng một phiên bản tổng quát hơn chuyển thể từ giải pháp Tomasz' ở trên mà xử lý tất cả các trường hợp Traversable

/** Implicit conversion for Traversable instances where the elements are convertable */ 
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] = 
    (input map c).asInstanceOf[I[T]] 

(Đây là làm việc cho tôi, mặc dù tôi muốn biết nếu có bất kỳ lập trình viên Scala nào có kinh nghiệm hơn nghĩ rằng đây là một ý tưởng tồi vì bất kỳ lý do nào, ngoài những lời khuyên thông thường về chuyển đổi ngầm)

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