سؤال

Option مناد هي طريقة تعبيرية رائعة للتعامل مع الأشياء أو الأشياء التي لا شيء في scala. ولكن ماذا لو لاحظ المرء تسجيل رسالة عندما يحدث "لا شيء"؟ وفقا لتوثيق Scala API،

غالبا ما يستخدم أي نوع كبديل ل SCALA.Option حيث يمثل اليسار الفشل (حسب الاتفاقية) واليمين هو أقرب إلى البعض.

ومع ذلك، لم أجد حظا للعثور على أفضل الممارسات باستخدام أمثلة عالمية حقيقية جيدة إما تتضمن إما لمعالجة الفشل. أخيرا، أتيت مع التعليمات البرمجية التالية لمشروعي الخاص:

    def logs: Array[String] = {
        def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
            val config = ca.getConfiguration(PID, null)
            config.properties getOrElse immutable.Map.empty
        }
        def checkType(any: Any): Option[Array[String]] = any match {
            case a: Array[String] => Some(a)
            case _ => None
        }
        def lookup: Either[(Symbol, String), Array[String]] =
            for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
                 val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
                 val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
            yield array

        lookup.fold(failure => { failure match {
            case ('warning, msg) => log(LogService.WARNING, msg)
            case ('debug, msg) =>   log(LogService.DEBUG, msg)
            case _ =>
        }; new Array[String](0) }, success => success)
    }

(يرجى ملاحظة أن هذا مقتطف من مشروع حقيقي، لذلك لن يترجم بمفرده)

سأكون ممتنا لمعرفة كيف تستخدمه Either في التعليمات البرمجية الخاصة بك و / أو أفضل الأفكار حول إعادة تكوين التعليمات البرمجية أعلاه.

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

المحلول

يتم استخدام إما لإرجاع أحد النتائج ذات المهتمين المحتملين، على عكس الخيار المستخدم لإرجاع نتيجة ذات معنى واحد أو لا شيء.

يتم إعطاء مثال سهل الفهم أدناه (Diamulated على القائمة البريدية SCALA لفترة أخرى):

def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] =
  try {
    Right(block)
  } catch {
    case ex => Left(ex)
  }

كما يعني اسم الوظيفة، إذا كان تنفيذ "كتلة" ناجحة، فسيعود "صحيح (u003Cresult> ) ". خلاف ذلك، إذا تم إلقاء القابلة للرمي، فسيعود" اليسار (u003Cthrowable> ) ". استخدم نمط مطابقة لمعالجة النتيجة:

var s = "hello"
throwableToLeft { s.toUpperCase } match {
  case Right(s) => println(s)
  case Left(e) => e.printStackTrace
}
// prints "HELLO"

s = null
throwableToLeft { s.toUpperCase } match {
  case Right(s) => println(s)
  case Left(e) => e.printStackTrace
}
// prints NullPointerException stack trace

امل ان يساعد.

نصائح أخرى

مكتبة Scalaz لها شيء على حد سواء إما تسمى التحقق من الصحة. من الناحية الاصطلاحية أكثر من الاستخدام ك "احصل على نتيجة صالحة أو فشل".

يسمح التحقق من الصحة أيضا لتجميع الأخطاء.

تحرير: "على حد سواء" إما غير كاذبة على الشيكيت، لأن التحقق من الصحة هو وظيفة وظيفية متطورة، و Scalaz إما، اسمه / (disfoncedction "أو" إما ")، هو موناد. حقيقة أن التحقق من الصحة يمكن أن يكرر الأخطاء هو بسبب هذه الطبيعة. من ناحية أخرى، / تتمتع بطبيعة "التوقف المبكرة" الطبيعة، والتوقف عند الأول - / (قرأتها "اليسار" أو "خطأ") وهي مواجهتها. هناك تفسير مثالي هنا: http://typelevel.org/blog/blog/2014/02/21/error-handling.html.

يرى: http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/exampledation.scala.html.

كما طلب التعليق، انسخ / لصق الرابط أعلاه (تمت إزالة بعض الخطوط):

// Extracting success or failure values
val s: Validation[String, Int] = 1.success
val f: Validation[String, Int] = "error".fail

// It is recommended to use fold rather than pattern matching:
val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString)

s match {
  case Success(a) => "success"
  case Failure(e) => "fail"
}

// Validation is a Monad, and can be used in for comprehensions.
val k1 = for {
  i <- s
  j <- s
} yield i + j
k1.toOption assert_≟ Some(2)

// The first failing sub-computation fails the entire computation.
val k2 = for {
  i <- f
  j <- f
} yield i + j
k2.fail.toOption assert_≟ Some("error")

// Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup.
// A number of computations are tried. If the all success, a function can combine them into a Success. If any
// of them fails, the individual errors are accumulated.

// Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor.
val k4 = (fNel <**> fNel){ _ + _ }
k4.fail.toOption assert_≟ some(nel1("error", "error"))

المفتطف الذي نشرته يبدو مفتعلا جدا. يمكنك استخدام إما في الموقف الذي:

  1. لا يكفي أن تعرف فقط البيانات غير متوفرة.
  2. تحتاج إلى إعادة واحدة من نوعين متميزين.

تحول استثناء في اليسار، في الواقع، حالة الاستخدام المشتركة. أكثر من TRY / CATCK، لديها ميزة إبقاء الكود معا، مما يجعل الشعور إذا كان الاستثناء نتيجة متوقعة. وبعد الطريقة الأكثر شيوعا للمناولة إما مطابقة نمط:

result match {
  case Right(res) => ...
  case Left(res) => ...
}

طريقة أخرى مثيرة للاهتمام للتعامل Either هو عندما يظهر في مجموعة. عند القيام بها خريطة عبر مجموعة، قد لا تكون رمي استثناء قابلة للحياة، وقد ترغب في إرجاع بعض المعلومات بخلاف "غير ممكن". استخدام إما يتيح لك القيام بذلك دون الإبطاء على الخوارزمية:

val list = (
  library 
  \\ "books" 
  map (book => 
    if (book \ "author" isEmpty) 
      Left(book) 
    else 
      Right((book \ "author" toList) map (_ text))
  )
)

هنا نحصل هنا على قائمة بجميع المؤلفين في المكتبة، زائد قائمة الكتب دون مؤلف. حتى نتمكن من معالجة هذا الأمر كذلك وفقا لذلك:

val authorCount = (
  (Map[String,Int]() /: (list filter (_ isRight) map (_.right.get))) 
   ((map, author) => map + (author -> (map.getOrElse(author, 0) + 1)))
  toList
)
val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation

لذلك، فإن الأساس إما يستخدم مثل هذا. إنها ليست فئة مفيدة بشكل خاص، ولكن إذا كنت قد رأيت ذلك من قبل. من ناحية أخرى، ليس عديم الفائدة أيضا.

القطط لديها طريقة لطيفة لإنشاء أي رمز رمي استثناء:

val either: Either[NumberFormatException, Int] =
  Either.catchOnly[NumberFormatException]("abc".toInt)
// either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")

في https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code.

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