Daha fazla yazım bilgisine ihtiyaç duyduğunuzda haklısınız ve genel olarak HList
ile bir değeriniz varsa Statik bir tip, muhtemelen yaklaşımınızı değiştirmeniz gerekecektir. HList
ile yapabileceğiniz hiçbir şey, HList
(buna değerlerini eklemenin yanı sıra) olduğu halde yapabileceğiniz hiç bir şey yoktur ve genellikle yalnızca HList
'u tip kısıtlaması olarak yazabilirsiniz.
Sizin durumunuzda, tanımladığınız şey, bir tür hizalanmış dizidir. Bu yaklaşımla ilerlemeden önce, gerçekten ihtiyacınız olduğuna gerçekten emin olmanızı öneririm. İşlevler (ve Conversion
gibi işlev benzeri türler) ile ilgili güzel şeylerden biri, oluşturdukları: A => B
ve B => C
öğeleriniz vardır ve bunları bir A => C
içine eklersiniz ve sonsuza kadar B
'u unutabilirsiniz. Genelde tam olarak istediğiniz gibi olan güzel ve temiz bir kara kutu elde edersiniz. Bununla birlikte, bazı durumlarda, işlev benzeri şeyleri, boru hattının parçalarını yansıtabileceğiniz şekilde oluşturabilmeniz yararlı olabilir. Bunun bu davalardan biri olduğunu kabul edeceğim, ama bunu kendiniz için doğrulamanız gerekir. Eğer değilse, şanslısınız çünkü gelecek olan karışıklıktır.
Bu tipleri varsayıyoruz:
import shapeless._
trait TypeAligned[L <: HList] extends DepFn1[L] {
type I <: Convertable
type O <: Convertable
type Out = Conversion[I, O]
}
L
:
trait Convertable
trait Conversion[A <: Convertable, B <: Convertable] {
def convert(a: A): B
}
Biz belirli HList
olan tipleri sıraya bir veya daha dönüşüm oluşur tanıklar bir tür sınıf tanımlayabilirsiniz Boru hattı ile ilgili tüm tip bilgileri içerir ve I
ve O
uç noktalarının türleridir.
Sonra (bu iki companioned edilecek için yukarıdaki özelliği ile birlikte tanımlanması gerekir unutmayın) bu tip sınıf için örneklerini gerekir:
object TypeAligned {
type Aux[L <: HList, A <: Convertable, B <: Convertable] = TypeAligned[L] {
type I = A
type O = B
}
implicit def firstTypeAligned[
A <: Convertable,
B <: Convertable
]: TypeAligned.Aux[Conversion[A, B] :: HNil, A, B] =
new TypeAligned[Conversion[A, B] :: HNil] {
type I = A
type O = B
def apply(l: Conversion[A, B] :: HNil): Conversion[A, B] = l.head
}
implicit def composedTypeAligned[
A <: Convertable,
B <: Convertable,
C <: Convertable,
T <: HList
](implicit
tta: TypeAligned.Aux[T, B, C]
): TypeAligned.Aux[Conversion[A, B] :: T, A, C] =
new TypeAligned[Conversion[A, B] :: T] {
type I = A
type O = C
def apply(l: Conversion[A, B] :: T): Conversion[A, C] =
new Conversion[A, C] {
def convert(a: A): C = tta(l.tail).convert(l.head.convert(a))
}
}
}
Şimdi de AutoConversion
bir sürümünü yazabilirsiniz boru hattı ile ilgili tip bilgilerin tümünü izler:
class AutoConversion[L <: HList, A <: Convertable, B <: Convertable](
path: L
)(implicit ta: TypeAligned.Aux[L, A, B]) extends Conversion[A, B] {
def convert(a: A): B = ta(path).convert(a)
}
Ve bu gibi kullanabilirsiniz:
case class AutoA(i: Int) extends Convertable
case class AutoB(s: String) extends Convertable
case class AutoC(c: Char) extends Convertable
val ab: Conversion[AutoA, AutoB] = new Conversion[AutoA, AutoB] {
def convert(a: AutoA): AutoB = AutoB(a.i.toString)
}
val bc: Conversion[AutoB, AutoC] = new Conversion[AutoB, AutoC] {
def convert(b: AutoB): AutoC = AutoC(b.s.lift(3).getOrElse('-'))
}
val conv = new AutoConversion(ab :: bc :: HNil)
Ve conv
beklenen statik türüne sahip olacak (ve Conversion[AutoA, AutoC]
uygulayın).