خيار موناد في سكالا
-
28-09-2019 - |
سؤال
كيف المقصود خيار العمل موناد؟ أنا أتصفح Scala API وهناك مثال (أعني الثاني) ،
بسبب كيفية عمل الفهم ، إذا لم يتم إرجاع أي شيء من request.getParameter ، فإن التعبير بأكمله ينتج عنه لا شيء
لكن عندما أحاول هذا الرمز:
val upper = for {
name <- None //request.getParameter("name")
trimmed <- Some(name.trim)
upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
} yield upper
println(upper.getOrElse(""))
أحصل على خطأ تجميع. كيف من المفترض ان يعمل هذا؟
المحلول
تحصل على خطأ في المترجم بسبب هذا
name <- None
بهذه الطريقة ، نوع من None
تم تعيينه على None.type
والمتغير name
يتم استنتاج ليكون من النوع Nothing
. (أي ، سيكون هذا النوع إذا كان موجودًا بالفعل ، لكن من الواضح أن الفهم لا يحصل حتى على إنشائه في وقت التشغيل.) لذلك لا توجد طريقة name.trim
موجود ولن يجمع.
إذا كان لديك request.getParameter("name")
متاح ، سيكون نوعه Option[String]
, name
من المحتمل أن يكون له نوع String
و name.trim
سوف تجمع.
يمكنك العمل حول هذا من خلال تحديد نوع من None
:
name <- None: Option[String]
نصائح أخرى
للتوسع في إجابة كيفن ، يمكنك تجنب التغلب على القيم Some()
باستخدام =
المشغل بدلاً من <-
المشغل أو العامل:
val upper = for {
name <- None: Option[String] //request.getParameter("name")
trimmed = name.trim
upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper
سوف يجمع الفهم إلى شيء مشابه جدًا لإصدار كيفن ، لكنني غالبًا ما أجد أنه أكثر وضوحًا للاستخدام map
و filter
صراحة لتجنب الفوضى (على سبيل المثال أسماء متغيرة إضافية) لا تضيف شيئًا إلى المحتوى الدلالي للتعبير.
للتوسع في إجابة Debilski ، لا تحتاج أيضًا إلى لف القيم اللاحقة صراحة في Some()
, ، القيمة الوحيدة التي تقوم بها بالفعل هي النسخة الأصلية name
.
سيكون النهج الأفضل هو استخدام map
و filter
العمليات مباشرة بدلاً من التفريغ:
ملاحظة: خلف الكواليس ، سيقوم برنامج التحويل البرمجي Scala بتحويل الفهم إلى مزيج من الخريطة/الفلتر/المرشح على أي حال ، لذلك لن يكون هذا النهج أقل كفاءة من الفهجة ، وقد يكون أكثر كفاءة
def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }
val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )