স্কালায় enum
জাভা যেমন টাইপ-সেফ নেই । সম্পর্কিত ধ্রুবকগুলির একটি সেট দেওয়া, ala ধ্রুবকদের প্রতিনিধিত্ব করার জন্য স্কালার সর্বোত্তম উপায় কী হবে?
স্কালায় enum
জাভা যেমন টাইপ-সেফ নেই । সম্পর্কিত ধ্রুবকগুলির একটি সেট দেওয়া, ala ধ্রুবকদের প্রতিনিধিত্ব করার জন্য স্কালার সর্বোত্তম উপায় কী হবে?
উত্তর:
http://www.scala-lang.org/docu/files/api/scala/Enumeration.html
উদাহরণ ব্যবহার
object Main extends App {
object WeekDay extends Enumeration {
type WeekDay = Value
val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
import WeekDay._
def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
WeekDay.values filter isWorkingDay foreach println
}
আমি অবশ্যই বলব উদাহরণস্বরূপ Scala ডকুমেন্টেশন আউট কপি দ্বারা skaffman উপরে বাস্তবে সীমিত উপযোগ হয় (আপনি হয়তো পাশাপাশি ব্যবহার case object
গুলি)।
জাভা সবচেয়ে সাদৃশ্যযুক্ত কিছু পাওয়ার জন্য Enum
(যেমন বুদ্ধিমান toString
এবং valueOf
পদ্ধতির সাথে - সম্ভবত আপনি একটি ডাটাবেসে এনাম মানগুলি চালিয়ে যাচ্ছেন) আপনার এটিকে কিছুটা সংশোধন করতে হবে। আপনি যদি স্কাফম্যানের কোড ব্যবহার করতেন :
WeekDay.valueOf("Sun") //returns None
WeekDay.Tue.toString //returns Weekday(2)
যেখানে নিম্নলিখিত ঘোষণাটি ব্যবহার করা হচ্ছে:
object WeekDay extends Enumeration {
type WeekDay = Value
val Mon = Value("Mon")
val Tue = Value("Tue")
... etc
}
আপনি আরও বুদ্ধিমান ফলাফল পান:
WeekDay.valueOf("Sun") //returns Some(Sun)
WeekDay.Tue.toString //returns Tue
valueOf
প্রতিস্থাপন হ'ল withName
, যা কোনও বিকল্প দেয় না এবং কোনও মিল না থাকলে কোনও এনএসই ফেলে দেয়। কি!
Map[Weekday.Weekday, Long]
এবং তাতে কোনও মান যুক্ত করার চেষ্টা করি তখন সংকলকটি Mon
একটি অবৈধ ধরণের ত্রুটি ছুড়ে দেয়। প্রত্যাশিত সপ্তাহের দিন. উইকডে মান খুঁজে পেয়েছে? কেন এমন হয়?
করার অনেকগুলি উপায় রয়েছে।
1) প্রতীক ব্যবহার করুন। এটি আপনাকে কোনও প্রকারের সুরক্ষা দেবে না, যদিও প্রতীক প্রত্যাশিত যেখানে অ-প্রতীকগুলি গ্রহণ না করে। আমি এখানে সম্পূর্ণতার জন্য এটি উল্লেখ করছি। ব্যবহারের উদাহরণ এখানে:
def update(what: Symbol, where: Int, newValue: Array[Int]): MatrixInt =
what match {
case 'row => replaceRow(where, newValue)
case 'col | 'column => replaceCol(where, newValue)
case _ => throw new IllegalArgumentException
}
// At REPL:
scala> val a = unitMatrixInt(3)
a: teste7.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 0 1 /
scala> a('row, 1) = a.row(0)
res41: teste7.MatrixInt =
/ 1 0 0 \
| 1 0 0 |
\ 0 0 1 /
scala> a('column, 2) = a.row(0)
res42: teste7.MatrixInt =
/ 1 0 1 \
| 0 1 0 |
\ 0 0 0 /
2) ক্লাস ব্যবহার Enumeration
:
object Dimension extends Enumeration {
type Dimension = Value
val Row, Column = Value
}
বা, যদি আপনার এটির ক্রমিক বা প্রদর্শন করতে হয়:
object Dimension extends Enumeration("Row", "Column") {
type Dimension = Value
val Row, Column = Value
}
এটি এর মতো ব্যবহার করা যেতে পারে:
def update(what: Dimension, where: Int, newValue: Array[Int]): MatrixInt =
what match {
case Row => replaceRow(where, newValue)
case Column => replaceCol(where, newValue)
}
// At REPL:
scala> a(Row, 2) = a.row(1)
<console>:13: error: not found: value Row
a(Row, 2) = a.row(1)
^
scala> a(Dimension.Row, 2) = a.row(1)
res1: teste.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 1 0 /
scala> import Dimension._
import Dimension._
scala> a(Row, 2) = a.row(1)
res2: teste.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 1 0 /
দুর্ভাগ্যক্রমে, এটি নিশ্চিত করে না যে সমস্ত ম্যাচ জবাবদিহি করা হয়েছে। আমি যদি ম্যাচে সারি বা কলামটি রাখতে ভুলে যাই, তবে স্কালার সংকলক আমাকে সতর্ক করে দিত না। সুতরাং এটি আমাকে কিছু ধরণের সুরক্ষা দেয় , তবে যতটা লাভ করা যায় ততটা নয়।
3) কেস অবজেক্টস:
sealed abstract class Dimension
case object Row extends Dimension
case object Column extends Dimension
এখন, আমি যদি match
একটির উপর একটি মামলা ছেড়ে যাই , সংকলক আমাকে সতর্ক করবে:
MatrixInt.scala:70: warning: match is not exhaustive!
missing combination Column
what match {
^
one warning found
এটি বেশ একইভাবে ব্যবহৃত হয় এবং এমনকি এটির প্রয়োজনও হয় না import
:
scala> val a = unitMatrixInt(3)
a: teste3.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 0 0 1 /
scala> a(Row,2) = a.row(0)
res15: teste3.MatrixInt =
/ 1 0 0 \
| 0 1 0 |
\ 1 0 0 /
আপনি ভাবতে পারেন, তবে কেস অবজেক্টের পরিবর্তে কেন কখনও এনুমুরেশন ব্যবহার করবেন। প্রকৃতপক্ষে, কেস অবজেক্টগুলির এখানে অনেকবার সুবিধা রয়েছে। এনুমারেশন ক্লাসে অনেকগুলি সংগ্রহের পদ্ধতি রয়েছে, যেমন উপাদানগুলি (স্কেলা ২.৮-এ পুনরুক্তি করা), যা একটি আইট্রেটর, মানচিত্র, ফ্ল্যাটম্যাপ, ফিল্টার ইত্যাদি প্রদান করে returns
এই উত্তরটি মূলত আমার ব্লগে এই নিবন্ধ থেকে একটি নির্বাচিত অংশ ।
Symbol
উদাহরণগুলির মধ্যে স্পেস বা বিশেষ অক্ষর থাকতে পারে না। বেশিরভাগ লোকেরা যখন প্রথম Symbol
শ্রেণীর মুখোমুখি হয় তখন সম্ভবত এটিই মনে হয় তবে আসলে এটি ভুল। Symbol("foo !% bar -* baz")
সংকলন এবং পুরোপুরি সূক্ষ্ম চালানো। অন্য কথায় আপনি নিখুঁতভাবে কোনও স্ট্রিং Symbol
মোড়ানো উদাহরণ তৈরি করতে পারেন (আপনি কেবল "একক কোমা" সিনট্যাকটিক চিনি দিয়ে এটি করতে পারবেন না)। গ্যারান্টি দেয় এমন একমাত্র বিষয় হ'ল কোনও প্রদত্ত প্রতীকটির স্বতন্ত্রতা, এটি তুলনামূলকভাবে তুলনামূলকভাবে এবং ম্যাচের তুলনায় সামান্য দ্রুত তৈরি করে। Symbol
String
একটি Symbol
প্যারামিটারের পক্ষে যুক্তি হিসাবে একটি পাস করতে পারবেন না ।
String
অন্য কোনও ক্লাসের সাথে প্রতিস্থাপন করেন যা মূলত একটি স্ট্রিংয়ের চারপাশে মোড়ক এবং উভয় দিক থেকে অবাধে রূপান্তর করা যায় (যেমনটি হয় তবে Symbol
)। আমার ধারণা, "এটি আপনাকে কোনও ধরণের সুরক্ষা দেবে না" বলার সময় আপনি কী বোঝাতে চেয়েছিলেন, ওপি স্পষ্টভাবে টাইপ নিরাপদ সমাধানের জন্য জিজ্ঞাসা করলেও এটি খুব পরিষ্কার ছিল না। আমি নিশ্চিত ছিলাম না যে লেখার সময় আপনি জানতেন যে এটি কেবল নিরাপদ টাইপ নয় কারণ সেগুলি মোটেই এনাম নয়, তবে এটিও Symbol
গ্যারান্টি দেয় না যে পাস হওয়া যুক্তিতে বিশেষ অক্ষর থাকবে না।
'foo
স্বরলিপি যা করে প্রতিরোধ অ-সনাক্তকারী স্ট্রিং)। এটি এই ভ্রান্ত ধারণাটি যে আমি ভবিষ্যতের যে কোনও পাঠকের জন্য তা দূর করতে চেয়েছিলাম।
নামযুক্ত গণনাগুলি ঘোষণার কিছুটা কম ভার্বোজ উপায়:
object WeekDay extends Enumeration("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat") {
type WeekDay = Value
val Sun, Mon, Tue, Wed, Thu, Fri, Sat = Value
}
WeekDay.valueOf("Wed") // returns Some(Wed)
WeekDay.Fri.toString // returns Fri
অবশ্যই এখানে সমস্যাটি হ'ল আপনার নাম এবং ভালসের ক্রমটি সিঙ্কে রাখা দরকার যা নাম এবং ভাল একই লাইনে ঘোষণা করা থাকলে করা সহজ।
আপনি অঙ্কের পরিবর্তে একটি সিলযুক্ত বিমূর্ত শ্রেণি ব্যবহার করতে পারেন, উদাহরণস্বরূপ:
sealed abstract class Constraint(val name: String, val verifier: Int => Boolean)
case object NotTooBig extends Constraint("NotTooBig", (_ < 1000))
case object NonZero extends Constraint("NonZero", (_ != 0))
case class NotEquals(x: Int) extends Constraint("NotEquals " + x, (_ != x))
object Main {
def eval(ctrs: Seq[Constraint])(x: Int): Boolean =
(true /: ctrs){ case (accum, ctr) => accum && ctr.verifier(x) }
def main(args: Array[String]) {
val ctrs = NotTooBig :: NotEquals(5) :: Nil
val evaluate = eval(ctrs) _
println(evaluate(3000))
println(evaluate(3))
println(evaluate(5))
}
}
সবেমাত্র এনুমারেটাম আবিষ্কার হয়েছে । এটি বেশ আশ্চর্যজনক এবং সমান আশ্চর্যজনক এটি আরও সুপরিচিত নয়!
স্কালায় "গণনা" এর চারপাশে সমস্ত অপশন সম্পর্কে বিস্তৃত গবেষণা করার পরে, আমি এই ডোমেনটির আরও একটি সম্পূর্ণ ওভারভিউ অন্য স্ট্যাকওভারফ্লো থ্রেডে পোস্ট করেছি । এটিতে "সিলড ট্রেইট + কেস অবজেক্ট" প্যাটার্নের একটি সমাধান অন্তর্ভুক্ত রয়েছে যেখানে আমি জেভিএম শ্রেণি / অবজেক্ট ইনিশিয়ালাইজেশন ক্রম সমস্যা সমাধান করেছি।
স্কালায় এটি খুব আরামদায়ক https://github.com/lloydmeta/enumeratum এর
প্রকল্প উদাহরণ এবং ডকুমেন্টেশন সহ সত্যিই ভাল
তাদের ডক্সের কেবল এই উদাহরণটি আপনাকে আগ্রহী করে তুলবে
import enumeratum._
sealed trait Greeting extends EnumEntry
object Greeting extends Enum[Greeting] {
/*
`findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
You use it to implement the `val values` member
*/
val values = findValues
case object Hello extends Greeting
case object GoodBye extends Greeting
case object Hi extends Greeting
case object Bye extends Greeting
}
// Object Greeting has a `withName(name: String)` method
Greeting.withName("Hello")
// => res0: Greeting = Hello
Greeting.withName("Haro")
// => java.lang.IllegalArgumentException: Haro is not a member of Enum (Hello, GoodBye, Hi, Bye)
// A safer alternative would be to use `withNameOption(name: String)` method which returns an Option[Greeting]
Greeting.withNameOption("Hello")
// => res1: Option[Greeting] = Some(Hello)
Greeting.withNameOption("Haro")
// => res2: Option[Greeting] = None
// It is also possible to use strings case insensitively
Greeting.withNameInsensitive("HeLLo")
// => res3: Greeting = Hello
Greeting.withNameInsensitiveOption("HeLLo")
// => res4: Option[Greeting] = Some(Hello)
// Uppercase-only strings may also be used
Greeting.withNameUppercaseOnly("HELLO")
// => res5: Greeting = Hello
Greeting.withNameUppercaseOnlyOption("HeLLo")
// => res6: Option[Greeting] = None
// Similarly, lowercase-only strings may also be used
Greeting.withNameLowercaseOnly("hello")
// => res7: Greeting = Hello
Greeting.withNameLowercaseOnlyOption("hello")
// => res8: Option[Greeting] = Some(Hello)