2016-02-21 14 views
6

tôi đùa giỡn xung quanh với HList và các công việc sau như mong đợi:Bắt yếu tố từ một HList

val hl = 1 :: "foo" :: HNil 
val i: Int = hl(_0) 
val s: String = hl(_1) 

Tuy nhiên, tôi không thể có được những đoạn mã sau đây làm việc (hãy giả sử một lúc truy cập ngẫu nhiên trên danh sách là một ý tưởng thông minh ;-)):

class Container(hl: HList) { 
    def get(n: Nat) = hl(n) 
} 

val container = new Container(1 :: "foo" :: HNil) 
val i: Int = container.get(_0) 
val s: String = container.get(_1) 

tôi muốn có get trả về một IntString theo đó là tham số. Tôi cho rằng, nếu có thể, tôi phải sử dụng Aux hoặc at nhưng tôi không chắc chắn cách thực hiện điều này.

Trả lời

4

Hãy thử một cái gì đó dọc theo những dòng này,

scala> import shapeless._, nat._, ops.hlist._ 
import shapeless._ 
import nat._ 
import ops.hlist._ 

scala> class Container[L <: HList](hl: L) { 
    | def get(n: Nat)(implicit at: At[L, n.N]): at.Out = hl[n.N] 
    | } 
defined class Container 

scala> val container = new Container(1 :: "foo" :: HNil) 
container: Container[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = ... 

scala> container.get(_0) 
res1: Int = 1 

scala> container.get(_1) 
res2: String = foo 

Sự khác biệt quan trọng đầu tiên ở đây là thay vì gõ hl như đồng bằng HList, mà mất tất cả thông tin cụ thể về các loại của các nguyên tố, chúng tôi parametrize so với loại chính xác của đối số và giữ nguyên cấu trúc của nó là L. Sự khác biệt thứ hai là chúng tôi sử dụng L để lập chỉ mục trường hợp lớp ẩn At tiềm ẩn được sử dụng để thực hiện lập chỉ mục trong get.

Cũng lưu ý rằng bởi vì có một chuyển đổi ngầm từ Int literals để Nat 's bạn có thể viết,

scala> container.get(0) 
res3: Int = 1 

scala> container.get(1) 
res4: String = foo 
+0

Tuyệt vời! Cảm ơn thư viện của bạn! – user3127060

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