سكالا حالة فئة مطابقة تجميع الخطأ مع أنواع الداخلية مستعارة؟

StackOverflow https://stackoverflow.com/questions/1812695

  •  06-07-2019
  •  | 
  •  

سؤال

وكيف يمكنني استخدام حالة مطابقة فئة مع أنواع مستعارة؟ هذا يعمل عندما سحب CB غيرها من الحاويات.

class DoStuff[TKey](
  val c : Container[TKey]#CB
)
{
  type CB = Container[TKey]#CB
  type C1 = Container[TKey]#C1
  type C2 = Container[TKey]#C2

  c match {
    case C1(e1) => e1  //   - not found: value e1   - not found: value C1
    case C2(e2) => e2 //    - not found: value e2   - not found: value C2
  }
}

trait Container[TKey]
{
    abstract trait CB
    case class C1(val e : AnyRef) extends CB
    case class C2(val e : AnyRef) extends CB
}

وشكرا!

هل كانت مفيدة؟

المحلول

والحق ... الطبقات الداخلية في سكالا هي ذكي قليلا. دعونا نحاول مثال بسيط قبل أن تظهر لك نسخة كتابتها من التعليمات البرمجية التي قدمت.

case class Foo(x: Int) {
  case class Bar(y: String) 
}

والآن، والنظر في التعليمات البرمجية المتكررة التالية:

val x = new Foo(1)
val y = new Foo(2)

val a = new x.Bar("one")
val b = new y.Bar("two") 

وهذا النوع أكثر من عام من a وb هو Foo#Bar، مما يعني أن Bar الطبقة الداخلية مع أي كائن الخارجي من نوع Foo. ولكن يمكن أن تكون أكثر تحديدا في القول أن هذا النوع من a هو x.Bar ونوع b هو y.Bar - وهو ما يعني أن a هو مثيل Bar الطبقة الداخلية مع x الكائن الخارجي، على غرار لb

ويمكنك أن ترى في الواقع أن أنواع مختلفة من خلال الدعوة typeOf(a) وtypeOf(b)، حيث typeOf هو أسلوب فائدة محددة على هذا النحو. (هو فقط يعطي نوع من الجدل من قبل لطيفا جدا نوع الاستدلال وقليلا من استخدام Manifests)

def typeOf[T](x: T)(implicit m: scala.reflect.Manifest[T]) = m.toString

وكما يحمل كائن الداخلي إشارة إلى كائن أرفق بها، وكنت <م> لا يمكن مثيل كائن الداخلي دون أن يحدد بطريقة أو بأخرى الكائن الخارجي. لذلك، يمكنك الاتصال new x.Bar("one") لكن لا يمكنك استدعاء new Foo#Bar("?") - كما في الحالة الثانية إذا لم تحدد ما هو الكائن الداخلي للكائن الجديد محاولة بناء

ولذا، دعونا العودة إلى مقتطف الشفرة. عندما كنت نمط مطابقة، كنت في الواقع استدعاء منشئ - عندما يدعو C1(e1). كما C1 هو اسم مستعار لContainer[TKey]#C1 حاولت استدعاء منشئ للفئة الداخلية دون تحديد موضوعها الخارجي، الذي فشل نظرا للأسباب المذكورة أعلاه. الطريقة أود أن أكتب رمز سيكون على النحو التالي:

trait Container[TKey] {
    abstract trait CB
    case class C1(val e : AnyRef) extends CB
    case class C2(val e : AnyRef) extends CB
}

class DoStuff[TKey] (val c: Container[TKey], val element: Container[TKey]#CB) {
  element match {
    case c.C1(e1) => Some(e1)
    case c.C2(e2) => Some(e2)
    case _        => None
  }
}

والآن هذا يجمع ونأمل أن تفعل ما تريد. ولكن اتخاذ هذا بعناية كبيرة! نظرا لنوع المحو، سكالا لا يمكن أن تضمن أن element هو في الواقع نوع من c.CB أو من نوع d.CB حيث CB في حالة c وd يحدث أن تكون هي نفسها.

وجرب هذا المثال:

def matcher(arg: Foo#Bar) = {
  arg match {
    case x.Bar(n) => println("x");
    case y.Bar(n) => println("y");
  }
}

وحيث x وy هي كما كانت من قبل. حاول تشغيل ما يلي:

matcher(a)
matcher(b) 

وكلاهما x الطباعة!

لذلك أود أن إعادة كتابة التعليمات البرمجية لديك صراحة عنصر في الحاوية:

trait Container[TKey] {
    abstract trait CB
    case class C1(val e : AnyRef) extends CB
    case class C2(val e : AnyRef) extends CB
    val element: CB
}

class DoStuff[TKey](val c: Container[TKey]) {
  c.element match {
    case c.C1(e1) => Some(e1)
    case c.C2(e2) => Some(e2)
    case _        => None
  }
}

ونأمل أن يساعد:)

و- Flaviu Cipcigan

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top