2014-05-08 13 views
6

Tôi đã viết một trình phân tích cú pháp để biến đổi một Chuỗi thành một Seq [Chuỗi] theo một số quy tắc. Điều này sẽ được sử dụng trong thư viện.Chuyển đổi một Seq [Chuỗi] thành một kiểu chữ theo cách an toàn

Tôi đang cố chuyển đổi Seq [Chuỗi] này thành một kiểu chữ. Lớp trường hợp sẽ được cung cấp bởi người dùng (vì vậy không có cách nào để đoán nó sẽ là gì).

Tôi đã nghĩ đến thư viện bất ổn vì nó dường như để thực hiện các tính năng tốt và có vẻ như trưởng thành, nhưng tôi không có ý tưởng làm thế nào để tiến hành.

Tôi đã tìm thấy câu hỏi này with an interesting answer nhưng tôi không tìm thấy cách chuyển đổi nó cho nhu cầu của mình. Thật vậy, trong câu trả lời chỉ có một kiểu để phân tích cú pháp (String), và thư viện lặp lại bên trong String. Nó có thể đòi hỏi một sự thay đổi sâu sắc trong cách mọi thứ được thực hiện, và tôi không có đầu mối như thế nào.

Hơn nữa, nếu có thể, tôi muốn làm cho quy trình này trở nên dễ dàng nhất có thể cho người dùng thư viện của tôi. Vì vậy, nếu có thể, không giống như câu trả lời trong liên kết ở trên, kiểu HList sẽ được đoán từ chính lớp vỏ (tuy nhiên theo tìm kiếm của tôi, có vẻ như trình biên dịch cần thông tin này).

Tôi hơi mới với hệ thống kiểu và tất cả những điều tuyệt đẹp này, nếu có ai có thể cho tôi lời khuyên về cách làm, tôi sẽ rất hạnh phúc!

Kind Regards

--- EDIT ---

Như ziggystar yêu cầu, đây là một số có thể có của các chữ ký cần thiết:

//Let's say we are just parsing a CSV. 

@onUserSide 
case class UserClass(i:Int, j:Int, s:String) 
val list = Seq("1,2,toto", "3,4,titi") 

// User transforms his case class to a function with something like: 
val f = UserClass.curried 

// The function created in 1/ is injected in the parser 
val parser = new Parser(f) 

// The Strings to convert to case classes are provided as an argument to the parse() method. 
val finalResult:Seq[UserClass] = parser.parse(list) 
// The transfomation is done in two steps inside the parse() method: 
// 1/ first we have: val list = Seq("1,2,toto", "3,4,titi") 
// 2/ then we have a call to internalParserImplementedSomewhereElse(list) 
// val parseResult is now equal to Seq(Seq("1", "2", "toto"), Seq("3","4", "titi")) 
// 3/ finally Shapeless do its magick trick and we have Seq(UserClass(1,2,"toto"), UserClass(3,4,"titi)) 



@insideTheLibrary 
class Parser[A](function:A) { 

//The internal parser takes each String provided through argument of the method and transforms each String to a Seq[String]. So the Seq[String] provided is changed to Seq[Seq[String]]. 
private def internalParserImplementedSomewhereElse(l:Seq[String]): Seq[Seq[String]] = { 
    ... 
} 

/* 
* Class A and B are both related to the case class provided by the user: 
* - A is the type of the case class as a function, 
* - B is the type of the original case class (can be guessed from type A). 
*/ 
private def convert2CaseClass[B](list:Seq[String]): B { 
    //do something with Shapeless 
    //I don't know what to put inside ??? 
} 

def parse(l:Seq[String]){ 
    val parseResult:Seq[Seq[String]] = internalParserImplementedSomewhereElse(l:Seq[String]) 
    val finalResult = result.map(convert2CaseClass) 
    finalResult // it is a Seq[CaseClassProvidedByUser]  
} 
}  

Bên trong thư viện một số tiềm ẩn sẽ có sẵn cho chuyển đổi String thành kiểu chính xác khi chúng được đoán bởi Shapeless (tương tự như câu trả lời được đề xuất trong liên kết ở trên). Giống như string.toInt, string.ToDouble, v.v ...

Có thể có cách khác để thiết kế nó. Nó chỉ là những gì tôi có trong tâm trí sau khi chơi với Shapeless vài giờ.

+3

Bạn có thể đăng mã minh họa những gì bạn mong đợi cuối cùng không? Chỉ chữ ký phương thức sẽ ổn thôi. Có thể chú thích chúng bằng 'thư viện' và' người dùng'. – ziggystar

+0

Bạn có thể đưa ra một ví dụ về một cuộc gọi đến convert2CaseClass và cũng phân tích cú pháp và kết quả sẽ là gì? –

+0

@DidierDupont Tôi đã thêm một số triển khai có thể có vào thư viện theo yêu cầu. Kết quả phải là danh sách các lớp chữ hoa chữ thường. Seq [String] -> Seq [Seq [String]] -> Seq [trường hợp lớp]. Chuyển đổi đầu tiên đã được mã hóa. Cái thứ hai là nơi tôi cần giúp đỡ. – pommedeterresautee

Trả lời

0

Câu trả lời này sẽ không cho bạn biết cách thực hiện chính xác những gì bạn muốn, nhưng nó sẽ giải quyết được vấn đề của bạn. Tôi nghĩ bạn đang làm quá nhiều thứ.

Bạn muốn làm gì? Dường như với tôi rằng bạn đơn giản đang tìm kiếm cách để serializedeserialize các trường hợp của bạn - tức là chuyển đổi đối tượng Scala thành định dạng chuỗi chung và định dạng chuỗi chung trở lại đối tượng Scala. Bước serialization của bạn hiện nay là một cái gì đó bạn dường như đã được xác định, và bạn đang hỏi về làm thế nào để làm deserialization.

Có một vài tùy chọn tuần tự hóa/deserialization có sẵn cho Scala. Bạn không cần phải hack với Shapeless hoặc Scalaz để tự mình làm. Hãy thử xem xét các giải pháp sau:

  1. Java serialization/deserialization. Các cơ sở tuần tự hóa/deserialization được cung cấp bởi môi trường Java. Yêu cầu truyền rõ ràng và cho phép bạn không kiểm soát định dạng tuần tự hóa, nhưng nó được tích hợp và không yêu cầu nhiều công việc để triển khai.
  2. Tuần tự hóa JSON: có nhiều thư viện cung cấp việc tạo và phân tích cú pháp JSON cho Java.Hãy xem ví dụ play-json, spray-jsonArgonaut.
  3. Thư viện Scala Pickling là thư viện tổng quát hơn để tuần tự hóa/deserialization. Trong số đó, nó đi kèm với một số nhị phân và một số định dạng JSON, nhưng bạn có thể tạo các định dạng của riêng bạn.

Trong số các giải pháp, ít nhất play-json và Scala phẩm làm sạch macro sử dụng để tạo ra serializers và deserializers cho bạn tại thời gian biên dịch. Điều đó có nghĩa là cả hai đều nên an toàn và thực hiện.

+0

Bạn đang đúng về những gì tôi muốn làm: Tôi muốn deserialize dây để trường hợp lớp.Nhưng tôi muốn làm cho nó automagick, tôi không muốn người sử dụng lib của tôi để Mỗi khi sử dụng Shapeless, tôi sẽ có thể nhận được Type of the case class, tôi có thể viết một số trình biến đổi ngầm để deserialize các kiểu phổ biến nhất (int, double, long ...) và cung cấp người sử dụng để cung cấp riêng của mình chuyển đổi (ngày, thời gian, bất cứ điều gì) .Đối với điều đó tôi thực sự cần shapeless.Vì tôi có một định dạng cụ thể để deserialize, tôi không thể sử dụng thư viện hiện có cho Json bạn đang liệt kê ở đây. – pommedeterresautee

+1

Tôi nghĩ rằng tôi đã hiểu sai câu hỏi một chút - nhưng vẫn còn, Scala Pickling thường nên theo hướng của những gì bạn muốn. Kiểm tra nó ra. – DCKing

+0

Tôi tìm một số ví dụ về sử dụng Scala Pickling, có vẻ thú vị lúc đầu, nhưng tôi thấy rằng bạn có thể cần tùy chỉnh deserializer cho định dạng tùy chỉnh của bạn cho từng loại bạn muốn sử dụng (có nghĩa là mỗi trường hợp lớp). Hơn nữa tài liệu rất mỏng. – pommedeterresautee

1

này sử dụng một thư viện rất đơn giản gọi là product-collecions

import com.github.marklister.collections.io._ 
case class UserClass(i:Int, j:Int, s:String) 

val csv = Seq("1,2,toto", "3,4,titi").mkString("\n") 
csv: String = 
1,2,toto 
3,4,titi 

CsvParser(UserClass).parse(new java.io.StringReader(csv)) 
res28: Seq[UserClass] = List(UserClass(1,2,toto), UserClass(3,4,titi)) 

Và để serialize theo cách khác:

scala> res28.csvIterator.toList 
res30: List[String] = List(1,2,"toto", 3,4,"titi") 

sản phẩm bộ sưu tập được định hướng về phía csv và java.io.Reader, vì thế mà shims ở trên.

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