سؤال

لدي رمز Scala Dummy التالي في الملف test.scala:

class Transaction {
  def begin() {}
  def commit() {}
  def rollback() {}
}

object Test extends Application {
  def doSomething() {}

  val t = new Transaction()
  t.begin()
  try {
    doSomething()
    t.commit()
  } catch {
    case _ => t.rollback()
  }
}

إذا قمت بتجميع هذا على Scala 2.8 RC1 مع scalac -Xstrict-warnings test.scala سأحصل على التحذير التالي:

test.scala:16: warning: catch clause swallows everything: not advised.
    case _ => t.rollback()
    ^
one warning found

لذا ، إذا لم يتم نصح تعبيرات كل شيء ، فكيف من المفترض أن أقوم بتنفيذ مثل هذا النمط بدلاً من ذلك؟ وبصرف النظر عن ذلك ، لماذا لا تنصح مثل هذه التعبيرات على أي حال؟

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

المحلول

يوجد التحذير لأنك ربما لا تريد التقاط كل شيء. على سبيل المثال ، من غير المستحسن عمومًا محاولة التقاط أي شيء java.lang.Error لأنه من الصعب في كثير من الأحيان التعافي من مثل هذه الأشياء. (من الجيد أن يتم طرحها من كتلة الصيد الخاصة بك باستثناء آخر.)

أيضًا ، نظرًا لأنه لا يمكنك التقاط كل شيء بشكل مفيد ، فهذه ليست طريقة آمنة لتنفيذ المعاملات الذرية/الآمنة. أنت أفضل حالًا بشيء مثل

try {
  t.commit()
} finally {
  if (!t.checkCommitted()) {
    t.rollback()
    if (!t.checkRolledback()) throw new FUBARed(t)
  }
}

مع اختبار إضافي عند القراءة في جديد t للتأكد من أنها في حالة معقولة.

نصائح أخرى

ليس لدي برنامج مترجم لتسليمه لاختبار هذا ، لكن ألا ينبغي أن تعيد ترسيخ الاستثناء بعد التراجع عن المعاملة؟ أي هذا يجب أن يكون

val t = new Transaction()
t.begin()
try {
  doSomething()
  t.commit()
} catch {
  case e => t.rollback(); throw e
}

إذا كنت تلتقط جميع الاستثناءات ، فيجب عليك ملاحظة الوثائق ل ControlThrowable. من المفترض أنك تريد أن تتراجع معاملتك إلى الإنهاء غير الطبيعي ، لكنها لا تريد أن تتراجع عن عودة غير محلية أو أ util.control.Breaks.break. إذا كان الأمر كذلك ، فقد ترغب في فعل شيء مثل ما يلي:

val t = new Transaction()
t.begin()
try {
  doSomething()
  t.commit()
} catch {
  case ce : ControlThrowable => throw ce // propagate
  case e => t.rollback(); throw e        // roll-back and propagate
}

أولاً ، لاحظ أن هذا تحذير ، وليس خطأ. على الرغم من ذلك ، فإن التحذير أثار فقط مع خيار -xstrict -warings. بمعنى آخر ، هذا يعني ذلك يمكن أنت ترتكب خطأ منطقيًا ، لكن الأمر متروك لك لاتخاذ قرار.

كما لاحظ الآخرون ، في معظم الحالات ، ليس من المفيد أن تلتقط كل الاستثناء ويجب أن تفعل شيئًا كهذا:

t.begin()
try {
  doSomething()
  t.commit()
} catch {
  case e: DuplicatedKeyError => ...
  case e: BrokenConnectionError => ...
  case e: DumbInputDetectedError => ...
}

أي التعامل مع جميع أنواع الأخطاء المعروفة.

ولكن إذا كنت إيجابيًا أنك تريد تجاهل (أو التعامل مع نفس الطريقة) كل الاستثناءات الممكنة ، فما عليك سوى تجاهل التحذير.

عليك أن تصطاد Throwable لتوضيح نيتك في اصطياد الجميع:

  try {
     android.util.Log.i (TAG, "Feature " + Text)
     statements
  }
  catch {
     case exception: Throwable =>
        val Message = "Feature " + Text + "failed"
        android.util.Log.e (TAG, Message, exception)
        fail (Message)
  } // try

المثال أعلاه إذا من اختبار الوحدة. كما يقول التحذير: لا ينصح في الكود العادي

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