לפני קריאת הפוסט הזה, אנא עבור על הפוסט הקודם שלי ב-"שאלות ראיון בסיסיות ותשובות בסיסיות בסקאלה" כדי להשיג מספר מושגים בסיסיים על שפת סקאלה. בפוסט הזה, אנו הולכים לדון על מספר שאלות נוספות בנושא שאלות ראיון בסקאלה שימושיות עבור מפתחי סקאלה מנוסים. הערה:- מאחר שרשימה זו כבר הפכה מאוד גדולה, אני הולך לפרסם פוסט נוסף עם השאלות והתשובות הנותרות. אנא התייחסו לפוסט זה בקישור: "שאלות ראיון בינוניות ומתקדמות בסקאלה ותשובות"
שאלות ראיון בסקאלה
בסעיף זה, אנו הולכים לרשום את כל שאלות הראיון הבינוניות בסקאלה ובסעיף הבא נדבר עליהן בפרט.
- מהו בנאי ראשי? מהו בנאי משני או עזר בסקאלה?
- מהו שימוש הבנאי העזר בסקאלה? אנא הסבר את החוקים למעקב אחריהם בהגדרת בנאיים עזר בסקאלה?
- מהם ההבדלים בין מערך ובין ArrayBuffer בסקאלה?
- מהו case class? מהו case object? מהם היתרונות של case class?
- מה ההבדל בין Case Object ובין Object (עצם רגיל)?
- אשר: בהשוואה למחלקה רגילה, מהם היתרונות המרכזיים או התועלות של Case-class?
- מה השימוש של שיטות isInstanceOf ו-asInstanceOf ב-Scala? האם יש כל דבר דומה זמין ב-Java?
- איך מוכח שבדרך כלל, Case Object הוא Serializable ו- Normal Object אינו?
- ההבחנה בין מערך ורשימה ב-Scala?
- מה ההבחנה בין "val" ו-"lazy val" ב-Scala? מהו הערכאות עקביות? מהו הערכאות עקבית?
- מהו הקשר בין equals method ו-== ב-Scala? הבחנה בין == ב-Scala ל-== ב-Java?
- ההבחנה בין מחלקה פנימית ב-Scala למחלקה פנימית ב-Java?
- מהו בעיה היהלומית? איך Scala פותרת את בעיה היהלומית?
- למה אין ל-Scala מילת מפתח "static"? מה הסיבה המרכזית להחלטה זו?
- מהו השימוש במילת המפתח "object" ב-Scala? איך ליצור אובייקטים יחידים ב-Scala?
- כיצד להגדיר שיטות מפענח באמצעות מילת המפתח "object" ב-Scala? מהו השימוש בהגדרת שיטות מפענח במילת המפתח "object"?
- מהו שיטת apply ב-Scala? מהו שיטת unapply ב-Scala? מה ההבחנה בין שיטות apply ו-unapply ב-Scala?
- איך זה עובד מתחת למכסה, כשאנו יוצרים מופע של מחלקה בלעדיים בשימוש במילת המפתח "new" ב-Scala? מתי נבחר בשיטה זו?
- איך מוגדרת מחלקת בנאי פרטית ב-Scala? איך לבצע קריאה לבנאי פרטי פרטי ב-Scala?
- האם מפעיל קומפניון גורם לגישה לאברים פרטיים של מחלקת הקומפניון שלו בסקאלה?
- מהו החלטת העיצוב העיקרית לגבי שני מילות מפתח נפרדות: מחלקה ואובייקט בסקאלה? איך אנחנו מגדירים אברי מופע ואברים סטטיים בסקאלה?
- מהו אובייקט בסקאלה? האם זהו אובייקט יחיד או מופע של מחלקה?
- מהו אובייקט מלווה בסקאלה? מהו מחלקת מלווה בסקאלה? מהו שימוש מופע מלווה בסקאלה?
- כיצד ליישם ממשקים בסקאלה?
- מהו טווח בסקאלה? כיצד ליצור טווח בסקאלה?
- כמה ערכים מסוג "שום דבר" יש בסקאלה?
- כמה ערכים מסוג "יחידה" יש בסקאלה?
- מהו טווח בסקאלה? כיצד ליצור טווח בסקאלה?
- ב- FP, מה ההבדל בין פונקציה לבין פרוצדורה?
- מהם ההבדלים העיקריים בין בנאי העזר של סקאלה לבין בנאי ה-Java?
- מהו השימוש של מילת המפתח "yield" במבנה התיאור של סקאלה עבור הבנה מלאה?
- מהו השומר במבנה התיאור של סקאלה?
- כיצד סקאלה פותרת באופן אוטומטי וקל יותר את בעיית היהלום של המורשת מאשר ג'אווה 8?
- בסקאלה, אילו דפוסי תאימות עוקבים? ב-Java, אופרטור ה-"isinstanceof" עוקב אחר אילו דפוסי תאימות?
שאלות ותשובות ראיונות ב-Scala
בסעיף זה, נבחן כל שאלה מהרשימה לעיל ונדון בה בעמימות עם דוגמאות מתאימות (אם נדרש). אם ברצונך להבין את המושגים הללו בעומק עם דוגמאות, אנא עיין בפוסטים הקודמים שלי בסעיף הלימודים של Scala.
מהו בנאי ראשי? מהו בנאי משני או עזר ב-Scala? מהו המטרה של בנאי העזר ב-Scala? האם אפשר להעמיס בנאים ב-Scala?
ב-Scala יש שני סוגים של בנאים:
- בנאי ראשי
- בנאי עזר
בנאי ראשי ב-Scala, בנאי ראשי הוא בנאי שמוגדר יחד עם הגדרת המחלקה עצמה. על כל מחלקה להיות בנאי ראשי אחד: בנאי עם פרמטרים או בנאי ללא פרמטרים. דוגמה: –
class Person
המחלקה Person שנמצאת מעלה כוללת בנאי ראשי בעל אפס פרמטרים, או ללא פרמטרים, או חסר פרמטרים ליצירת מופעים של מחלקה זו.
class Person (firstName: String, lastName: String)
המחלקה Person שנמצאת מעלה כוללת בנאי ראשי בעל שני פרמטרים ליצירת מופעים של מחלקה זו. בנאי עזר הבנאי העזר ידוע גם כבנאי משני. אנו יכולים להגדיר בנאי משני באמצעות מילות המפתח 'def' ו-'this' כפי שמוצג למטה:
class Person (firstName: String, middleName:String, lastName: String){
def this(firstName: String, lastName: String){
this(firstName, "", lastName)
}
}
מהו השימוש של בנאיים עזר ב־Scala? אנא הסבר על הכללים לעקוב אחריהם בהגדרת בנאיים עזר ב־Scala?
ב־Scala, המטרה העיקרית של בנאיים עזר היא לעמוד בעומס על בנאים. כמו ב־Java, אנו יכולים לספק מגוון של בנאים כך שהמשתמש יכול לבחור את הנכון ביותר לפי דרישותיו. כללי בנאי עזר:
- הם דומים לשיטות בלבד. כמו שיטות, עלינו להשתמש במילת המפתח 'def' כדי להגדיר אותם.
- עלינו להשתמש באותו שם 'this' עבור כל בנאי עזר.
- כל בנאי עזר צריך להתחיל עם קריאה לבנאי עזר אחר שהוגדר מראש או לבנאי ראשי. אחרת יתרחש שגיאת זמן קומפילציה.
- כל בנאי עזר צריך להשתנות עם רשימת הפרמטרים שלו: יכול להיות לפי מספר או סוגים.
- בנאי עזר אינם יכולים לקרוא לבנאי של מחלקת ההורשה. עליהם לקרוא אליהם דרך בנאי הראשי בלבד.
- כל בנאי עזר קורא לבנאי הראשי שלו באופן ישיר או עקיף דרך בנאיים עזר אחרים.
הערה:- אם ברצונך ללמוד על בנאים בשפת סקאלה, אנא הפנה לפוסטים שלי בסקאלה ב: בנאי ראשי ו בנאי עזר.
מה ההבדלים בין מערך ובין ArrayBuffer בסקאלה?
ההבדלים בין מערך ו-ArrayBuffer בסקאלה:
- מערך הוא מערך בגודל קבוע. אין אפשרות לשנות את גודלו לאחר שנוצר.
- ArrayBuffer הוא מערך בגודל משתנה. הוא יכול להגדיל או להפחית את גודלו באופן דינמי.
- מערך הוא משהו דומה למערכי הפרימיטיבים של Java.
- ArrayBuffer הוא משהו דומה ל-ArrayList של Java.
מהו case class? מהו case object? מהם היתרונות של case class?
case class הוא מחלקה שמוגדרת עם מילות המפתח "case class". case object הוא אובייקט שמוגדר עם מילות המפתח "case object". עקב המילה "case" נקבל כמה יתרונות למניעת קוד מיותר. נוכל ליצור אובייקטים של case class מבלי להשתמש במילת המפתח "new". כברירת מחדל, מהדר Scala מוסיף קידומת "val" לכל פרמטרי הבנאי. לכן, בלי להשתמש ב-val או var, פרמטרי הבנאי של case class יהפכו לחברי מחלקה, וזה אינו אפשרי למחלקות רגילות. יתרונות של case class:
- לפי ברירת המחדל, מהדר Scala מוסיף את הפונקציות toString, hashCode ו-equals. אנו יכולים למנוע את כתיבת קוד זה מיותר.
- לפי ברירת המחדל, מהדר Scala מוסיף אובייקט לוֹסף עם פונקציות apply ו-unapply ולכן לא נזדקק למילת המפתח new כדי ליצור מופעים של case class.
- לפי ברירת המחדל, מהדר Scala מוסיף גם את הפונקציה copy.
- אנו יכולים להשתמש ב-case classes בתיאורת תבניות.
- לפי ברירת המחדל, case class ו-case objects הם ניתנים לשימור.
מה ההבחנה בין Case Object לבין Object (Normal Object)?
- אובייקט רגיל נוצר באמצעות מילת "object". לברירת מחדל, זהו אובייקט יחיד.
object MyNormalObject
- Case Object נוצר באמצעות "case object" ולברירת מחדל, גם זהו אובייקט יחידמילות מפתח.
case object MyCaseObject
- בברירת מחדל, ל-Case Object יש שיטות toString ו- hashCode. אבל אובייקט רגיל אין לו.
- בברירת מחדל, Case Object הוא Serializable. אבל אובייקט רגיל אינו.
בהשוואה למחלקה רגילה, מהם היתרונות העיקריים של Case Class?
היתרונות או התועלות העיקריים של Case Class מול מחלקות רגילות הם:
- מניעת המון קוד חסר עוני על ידי הוספת של מתודות שימושיות באופן אוטומטי.
- בברירת מחדל, תמיכה בלשוניות מכיוון שהפרמטרים שלה הם 'val'
- קל לשימוש בתיאום דפוסים.
- אין צורך להשתמש במילת המפתח 'new' כדי ליצור מופע של Case Class.
- לפי ברירת מחדל, תומך בסדרת המרה והשמה.
מהו השימוש של שיטות isInstanceOf ו- asInstanceOf ב-Scala? האם יש יישות דומה זמינה ב-Java?
שתי השיטות isInstanceOf ו- asInstanceOf מוגדרות במחלקת Any. לכן אין צורך לייבא אותן כדי לקבל את השיטות אלו לתוך כל מחלקה או אובייקט. השיטה "isInstanceOf" משמשת לבדיקה האם האובייקט הוא מסוג נתון או לא. אם כן, היא מחזירה אמת. אחרת, היא מחזירה שקר.
scala> val str = "Hello"
scala>str.isInstanceOf[String]
res0: Boolean = false
השיטה "asInstanceOf" משמשת להמיר את האובייקט לסוג הנתון. אם האובייקט הנתון והסוג זהים, היא ממירה אותו לסוג הנתון. אחרת, היא משגיחה חריגת java.lang.ClassCastException.
scala> val str = "Hello".asInstanceOf[String]
str: String = Hello
ב-Java, מילת המפתח 'instanceof' דומה לשיטת 'isInstanceOf' של Scala. ב-Java, סוג ההמרה הידנית הבאה דומה לשיטת 'asInstanceOf' של Scala.
AccountService service = (AccountService)
context.getBean("accountService");
איך ניתן להוכיח כי לפי ברירת המחדל, Case Object הוא Serializable ואובייקט רגיל אינו?
כן, כברירת מחדל, Case Object הוא Serializable. אך Object רגיל אינו. אנו יכולים להוכיח זאת באמצעות שימוש בשיטת isInstanceOf כפי שמוצג למטה:
scala> object MyNormalObject
defined object MyNormalObject
scala> MyNormalObject.isInstanceOf[Serializable]
res0: Boolean = false
scala> case object MyCaseObject
defined object MyCaseObject
scala> MyCaseObject.isInstanceOf[Serializable]
res1: Boolean = true
מה ההבחנה בין מערך לרשימה ב־Scala?
- מערכים תמיד הם Mutable בניגוד לרשימה שתמיד היא Immutable.
- פעם שנוצר, אנו יכולים לשנות ערכי מערך, בעוד שלא יכולים לשנות אובייקט של רשימה.
- מערכים הם מבני נתונים בגודל קבוע, בעוד שרשימה היא מבנה נתונים בגודל משתנה. גודל הרשימה מתכוונן אוטומטית על פי הפעולות שבוצעו עליה.
- מערכים הם Invariants בעוד שרשימות הן Covariants.
הערה: אם אינך בטוח לגבי Invariant ו־Covariant, אנא קרא את הפוסט הבא שלי על שאלות ראיונות ב־Scala.
מה ההבחנה בין "val" ובין "lazy val" ב־Scala? מהו הערכת נמוכים? מהו הערכת עצלון?
כפי שדובר בשאלות ראיונות ב־Scala הבסיסיות שלי, "val" אומר ערך או קבוע שמשמש להגדיר משתנים Immutable. ישנם שני סוגים של הערכה בתכנית:
- הערכת נמוכה
- הערכת נמוכה
הערכת נמוכה משמעותה הערכת תוכנית בזמן קידוד או בזמן ההפצה של התוכנית בלתי תלוי אם הלקוחות משתמשים בתוכנית ההפקה או לא. הערכת עצלנית משמעותה הערכת תוכנית בזמן ריצה לפי דרישת הלקוח, כלומר רק כאשר הלקוחות גוששים את התוכנית, היא מתוכננת. ההבדל בין "val" ל-"lazy val" הוא ש-"val" משמשת להגדרת משתנים שמתוכננים באופן עצל ו-"lazy val" גם היא משמשת להגדרת משתנים אך הם מתוכננים באופן עצל.
מהו הקשר בין שיטת equals ובין == ב-Scala? להבדיל בין == ב-Scala לבין האופרטור == ב-Java?
ב-Scala, אנו אינו צריכים לקרוא לשיטת equals() כדי להשוות שני מופעים או עצמים. כאשר אנו משווים שני מופעים עם ==, Scala קוראת לשיטת equals() של האובייקט הזה באופן אוטומטי. האופרטור == של Java משמש לבדיקת השיוויון של הפניות, כלומר האם שתי הפניות מצביעות על אותו אובייקט או לא. ה-== של Scala משמש לבדיקת השוואה של מופעים, כלומר האם שני מופעים שווים או לא.
ההבדל בין מחלקת פנימית ב-Scala לבין מחלקה פנימית ב-Java?
ב-Java, מחלקה פנימית מקושרת למחלקת חיצונית שהיא חברה של מחלקת החיצונית. להבדיל מ-Java, Scala טופלת את היחס בין מחלקה חיצונית ומחלקה פנימית באופן שונה. מחלקת פנימית ב-Scala מקושרת לאובייקט של מחלקה חיצונית.
מהו הבעיה של המשולש? איך Scala פותרת את בעית המשולש?
A Diamond Problem is a Multiple Inheritance problem. Some people calls this problem as Deadly Diamond Problem. In Scala, it occurs when a Class extends more than one Traits which have same method definition as shown below. Unlike Java 8, Scala solves this diamond problem automatically by following some rules defined in Language. Those rules are called “Class Linearization”. Example:-
trait A{
def display(){ println("From A.display") }
}
trait B extends A{
override def display() { println("From B.display") }
}
trait C extends A{
override def display() { println("From C.display") }
}
class D extends B with C{ }
object ScalaDiamonProblemTest extends App {
val d = new D
d display
}
כאן הפלט הוא "From C.display" מתוך trait C. מהדיקוד של Scala, "extends B with C" נקרא מימין לשמאל ולוקח את ההגדרה של השיטה "display" מהתכונה הכי שמאלית שהיא C. הערה:- ראו את הפוסט שלי על "תכונות ב-Scala בעומק" כדי להבין זאת עם הסבר ברור.
למה Scala לא מכילה את המילה השמורה "static"? מהו הסיבה העיקרית להחלטה זו?
כפי שאנו יודעים, ב-Scala אין מילת מפתח "static" כלל. זו החלטת עיצוב שביצעה צוות Scala. הסיבה המרכזית להחלטה זו היא להפוך את Scala לשפת תכנות אובייקטית טהורה. מילת המפתח "static" משמעה שניתן לגשת לחברי המחלקה הללו בלעדיו שליצור אובייקט או בלעדיו שלשימוש באובייקט. זה הולם תחומי עקרונות של תכנות חזותי. כאשר שפה תומכת ב-"static" keyword, היא אינה שפה אובייקטית טהורה. לדוג, Java תומכת במילת מפתח "static", ולכן אינה שפת תכנות אובייקטית טהורה. בניגוד לכך, Scala היא שפת תכנות אובייקטית טהורה.
מהו השימוש במילת המפתח "object" ב-Scala? איך ליצור אובייקטים יחידים ב-Scala?
ב-Scala, מילת המפתח "object" משמשת למטרות הבאות:
- היא משמשת ליצירת אובייקט יחיד (Singleton) ב-Scala.
object MySingletonObject
כאשר יוצרים את MySingletonObject כמובן יחיד, מילת המפתח "object" משמשת גם להגדרת יישומונים ב-Scala המהווים תכניות Scala ניתןות להרצה.
object MyScalaExecutableProgram{
def main(args: Array[String]){
println("Hello World")
}
}
כאשר אנו מגדירים את השיטה הראשית (main) באובייקט כפי שהוצג למעלה (דומה ל-main() ב-Java), היא מתפקדת אוטומטית כתכנית Scala ניתנת להרצה. מילת המפתח "object" נעשית שימוש גם להגדרת חברים סטטיים כמו משתנים ושיטות סטטיות בלעדיים ללא שימוש במילת המפתח "static".
object MyScalaStaticMembers{
val PI: Double = 3.1414
def add(a: Int, b: Int) = a + b
}
על ידי הגדרת משתנה PI ושיטות add כחברים סטטיים, אנחנו יכולים לקרוא להם בלי ליצור אובייקט נפרד כמו MyScalaStaticMembers.add(10,20).- זה משמש להגדיר שיטות יצור. נא לעיין בשאלה הבאה שלי על נושא זה.
איך מגדירים שיטות יצור באמצעות מילת המפתח object ב-Scala? מה השימוש של הגדרת שיטות יצור באמצעות אובייקט?
ב-Scala, אנחנו משתמשים במילת המפתח 'object' כדי להגדיר שיטות יצור. המטרה העיקרית של שיטות הייצור הללו ב-Scala היא למנוע שימוש במילת המפתח 'new'. בלתי אפשר ליצור אובייקטים בלי להשתמש במילת המפתח 'new'. כדי להגדיר שיטות יצור: אנחנו יכולים להשתמש בשיטת apply כדי להגדיר שיטות יצור ב-Scala. אם יש לנו בנאי ראשי ומספר בנאים עזרים, אז עלינו להגדיר מספר שיטות apply כמופיע להלן.
class Person(val firstName: String, val middleName: String, val lastName: String){
def this(firstName: String, lastName: String){
this(firstName,"",lastName)
}
}
object Person{
def apply(val firstName: String, val middleName: String, val lastName: String)
= new Person(firstName,middleName,lastName)
def apply(val firstName: String, val lastName: String)
= new Person(firstName, lastName)
}
כעת אנחנו יכולים ליצור אובייקטים של Person בלתי אפשר בלי להשתמש במילת המפתח new או עם מילת המפתח new לפי ההעדפה שלך.
val p1 = new Person("Scala","Java")
or
val p1 = Person("Scala","Java")
מהו שיטת apply ב־Scala? מהו שיטת unapply ב־Scala? מה ההבדל בין שיטות apply ו־unapply ב־Scala?
בְּScala, שיטות apply ו־unapply משמשות תפקיד חשוב מאוד. הן גם מאוד שימושיות בְּפריימוורק Play במיפוי ובאימפייה של נתונים בין נתוני טופס ונתוני מודל. במילים פשוטות,
- שיטת apply: להרכיב או לקבץ אובייקט מהרכיבים שלו.
- שיטת unapply: לפרוק או לפרק אובייקט לרכיביו.
שיטת apply של Scala: משמשת ליצירת אובייקט על ידי שימוש ברכיביו. לדוגמה אם נרצה ליצור אובייקט של Person, אז נשתמש ברכיבי firstName ו־lastName ונרכיב את האובייקט Person כפי שמוצג למטה.
class Person(val firstName: String, val lastName: String)
object Person{
def apply(firstName: String, lastName: String)
= new Person(firstName, lastName)
}
שיטת unapply של Scala: משמשת לפירוק אובייקט לרכיביו. היא עוקבת אחר תהליך הפוך של שיטת apply. לדוגמה אם יש לנו אובייקט של Person, אז נוכל לפרק את האובייקט הזה לשני רכיביו: firstName ו־lastName כפי שמוצג למטה.
class Person(val firstName: String, val lastName: String)
object Person{
def apply(firstName: String, lastName: String)
= new Person(firstName, lastName)
def unapply(p: Person): (String,String)
= (p.firstName, p.lastName)
}
כיצד זה עובד מתחת לציפוי, כאשר אנו יוצרים מופע של מחלקה בלי להשתמש במילת המפתח 'new' ב־Scala? מתי אנו בוחרים בגישה זו? איך להצהיר על בנאי פרטיים ב־Scala?
ב־Scala, כאשר אנו יוצרים מופע של מחלקה מבלי להשתמש במילת המפתח 'new', מפנים הוא עושה קריאה לפונקציית apply המתאימה הזמינה באובייקט המלווה. כאן, פונקציית apply המתאימה מתכוונת לפונקציה המתאימה לפי הפרמטרים.מתי אנו בוחרים באפשרות זו: כאשר אנו צריכים לספק בנאי פרטי ורוצים להימנע משימוש במילת המפתח 'new', אנו יכולים לממש רק את פונקציית apply עם אותו סט של פרמטרים ולאפשר למשתמשים במחלקה ליצור אותה בלי מילת המפתח new.
איך אנחנו מצהירים קונסטרקטור ראשי פרטי ב־Scala? איך אנחנו קוראים לקונסטרקטור ראשי פרטי ב־Scala?
ב־Scala, אנו יכולים להגדיר קונסטרקטור ראשי פרטי בקלות רבה. פשוט ציינו קונסטרקטור ראשי כפי שהוא והוסיפו 'פרטי' מיד אחרי שם המחלקה ולפני רשימת הפרמטרים כפי שמוצג למטה:
class Person private (name: String)
object Person{
def apply(name: String) = new Person(name)
}
כיוון שזהו קונסטרקטור פרטי, אין באפשרותנו לקרוא אותו מחוץ למחלקה. עלינו לספק שיטת יצרן (כלומר שיטת apply) כפי שמוצג למעלה ולהשתמש בקונסטרקטור זה באופן עקיף.
האם אובייקט מלווה יכול לגשת לחברי הפרטיים של המחלקה שלו ב־Scala?
בדרך כלל, חברים פרטיים אומרים נגישים רק בתוך המחלקה הזו. אך ב־Scala, כיתה מלווה ואובייקט מלווה סיפקו תכונה נוספת. ב־Scala, אובייקט מלווה יכול לגשת לחברי הפרטיים של המחלקה שלו ומחלקת המלווה יכולה לגשת לחברי הפרטיים של אובייקט המלווה שלה.
מהו ההחלטה העיקרית בעיצוב של שני מילים מפרדות: class ו-object ב-Scala? איך אנו מגדירים את חברי המופע וחברי הסטטי ב-Scala?
ב-Scala, אנו משתמשים במילה class להגדיר חברי מופע ובמילה object להגדיר חברי סטטי. ב-Scala אין מילת מפתח סטטית, אך עדיין ניתן להגדיר אותם באמצעות מילה object. ההחלטה העיקרית בעיצוב זה היא ההפרדה הברורה בין חברי המופע וחברי הסטטי. זהו קישור פתוח ביניהם. וסיבה נוספת חשובה היא להימנע ממילת המפתח static כך ש-Scala תהיה שפת תכנות אובייקטית טהורה.
מהו object ב-Scala? האם זהו אובייקט יחיד או מופע של מחלקה?
בניגוד ל-Java, ב-Scala יש שני משמעויות למילה 'object'. אל תתבלבל בנוגע לכך, אני אסביר באופן ברור. ב-Java יש לנו רק משמעות אחת למילה 'object' והיא "מופע של מחלקה".
- כמו ב-Java, המשמעות הראשונה של 'object' ב-Scala היא "מופע של מחלקה".
val p1 = new Person("Scala","Java")
or
val p1 = Person("Scala","Java")
- המשמעות השנייה היא ש- object הוא מילת מפתח ב-Scala. זה משמש להגדרת תוכניות Scala ברתימות, אובייקטים מלווים, אובייקטים יחידים וכו'
מהו אובייקט מלווה ב-Scala? מהו מחלקת מלווה ב-Scala? מהו שימושו של אובייקט מלווה ב-Scala?
במילים פשוטות, אם מחלקה ואובייקט ב-Scala משתפים את אותו השם ומוגדרים באותו קובץ מקור, אז המחלקה הזו ידועה כ"מחלקת מלווה" והאובייקט הזה ידוע כ"אובייקט מלווה". כאשר אנו יוצרים מחלקה באמצעות מילת המפתח "class" של Scala ואובייקט באמצעות מילת המפתח "object" של Scala עם אותו השם ובאותו קובץ מקור, אז המחלקה הזו ידועה כ"מחלקת מלווה" והאובייקט הזה ידוע כ"אובייקט מלווה". לדוגמה:- Employee.scala
class Employee{ }
object Employee{ }
ב-Scala, המטרה העיקרית של אובייקט מלווה היא להגדיר את שיטת apply ולמנוע את השימוש במילת המפתח new ביצירת מופע של אותו אובייקט מחלקה.
כיצד ליישם ממשקים ב-Scala?
כפי שאנו יודעים מרקע Java, אנו משתמשים בממשק כדי להגדיר את הקשר. אולם, אין קיום למונח ממשק ב-Scala. בעצם, Scala אינה מכילה מילת מפתח ממשק. במקום זאת, ישנה ב-Scala רעיון יותר עוצמתי וגמיש – trait.
מהו טווח ב-Scala? איך מתבצע יצירת טווח ב-Scala?
טווח הוא אוסף עצל ב-Scala. טווח הוא מחלקה הזמינה בחבילת 'scala', כמו 'scala.Range'. משמשת לייצוג רצף של ערכי מספרים שלמים. זוהי רצף ממוין של מספרים שלמים. דוגמה:
scala> 1 to 10
res0: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> 1 until 10
res1: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
כמה ערכים מסוג Nothing יש ב-Scala?
ב-Scala, טיפוס Nothing אין לו ערכים, כלומר אפס. הוא אינו מכיל ערכים. זוהי תת-סוג של כל המחלקות של ערכי ערך ומחלקות הפניה.
כמה ערכים מסוג Unit יש ב-Scala?
().
בְּשְׂפַת Scala, Unit הוא משהו דומה למילת המפקד void של Java. הוא משמש לייצג "אין ערך". יש לו ערך יחיד ובלעדי, הוא ().
A pure function is a function without any observable side-effects. That means it returns always same results irrespective how many times we call it with same inputs. A pure function always gives same output for the same inputs. For Example:-
scala> 10 + 20
res0: Int = 30
scala>
scala> 10 + 20
res0: Int = 30
מהו פונקציה טהורה?
בפרדיגמת התכנות הפונקציונלית, מהי ההבחנה בין פונקציה לבין פרוצדורה?
מהם ההבחנים המרכזיים בין בנאי השפה Scala המסייעים ובין בנאי השפה Java?
הבנאי המסייע של Scala דומה כמעט לבנאי של Java עם מספר הבדלים. בהשוואה לבנאי של Java, הבנאי המסייע ב-Scala מציין את ההבדלים הבאים:
- הבנאי המסייע נקרא באמצעות מילת המפתח "this".
- כל בנאי מסייע מוגדר עם אותו השם, "this". ב-Java, אנו משתמשים בשם המחלקה כדי להגדיר בנאים.
- כל בנאי מסייע חייב להתחיל עם קריאה לבנאי מסייע שכבר הוגדר או לבנאי הראשי.
- אנו משתמשים במילת המפתח 'def' כדי להגדיר בנאים מסייעים כמו הגדרת פונקציות/שיטות. ב-Java, הגדרת בנאי והגדרת שיטה הן שונות.
מהו השימוש של המילה המפתח 'yield' במבנה ה-for-comprehension של Scala?
אנו יכולים להשתמש במילת המפתח 'yield' במבנה ה-for-comprehension של Scala. 'for/yield' משמש לעיבוד אוסף של איברים ויוצר אוסף חדש באותו הסוג. זה אינו משנה את האוסף המקורי, אלא מייצר אוסף חדש באותו הסוג כמו סוג האוסף המקורי. לדוגמה, אם נשתמש במבנה 'for/yield' כדי לעבור על רשימה, הוא יייצר רשימה חדשה בלבד.
scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)
scala> for(l <- list) yield l*2
res0: List[Int] = List(2, 4, 6, 8, 10)
מהו ה-Guard במבנה ה־for-comprehension של Scala?
ב־Scala, מבנה ה־for-comprehension מכיל תנאי if אשר משמש לכתיבת תנאי לסינון של איברים וליצירת אוסף חדש. תנאי זה נקרא גם "Guard". אם ה־guard הוא נכון, אז האיבר מתווסף לאוסף החדש. במקרה אחר, האיבר לא מתווסף לאוסף המקורי. דוגמה:- מבנה ה־for-comprehension עם guard ליצירת מספרים זוגיים בלבד באוסף חדש.
scala> val list = List(1,2,3,4,5,6,7,8,9,10)
list: List[Int] = List(1, 2, 3, 4, 5 , 6 , 7 , 8 , 9 , 10)
scala> for(l <- list if l % 2 =0 ) yield l
res0: List[Int] = List(2, 4, 6, 8, 10)
איך Scala פותרת בעיה של היהלום של ההורשה באופן אוטומטי ובקלות יותר מ־Java 8?
כאשר אנו משתמשים בממשק של Java 8 עם שיטות ברירת מחדל, אנו מתמודדים עם בעיה של היהלום של ההורשה. המפתח צריך לפתור את הבעיה באופן ידני ב־Java 8. היא לא מספקת פתרון ברירת מחדל או אוטומטי לבעיה זו. ב־Scala, נתקלים באותה בעיה עם Traits אך Scala די חכמה ופותרת את בעית ההיהלום של ההורשה באופן אוטומטי באמצעות המושג של Linearization של מחלקות.
בְּשָׁפַת סְקָאלָה, הִתְאָמַת דּוֹגְמָה נִמְצָאָה בִּתְבִיעַת עֵיצוּר. בִּשְׂפַת ג'אווה, אוֹפֶרְטוֹר 'instanceof' נִמְצָא בִּתְבִיעַת עֵיצוּר.
בְּשָפַת סְקָאלָה, הִתְאָמַת דּוֹגְמָה נִמְצָאָה בִּתְבִיעַת הַמְּבַקֵּר. בְּאוֹפֶן דוֹמֶה, אוֹפֶרְטוֹר 'instanceof' שֶׁל ג'אווה גַּם הוּא נִמְצָא בִּתְבִיעַת הַמְּבַקֵּר. זֶהוּ כֹּל מַה שֶׁיֵּשׁ בְּנוֹגֵעַ לְ"שְׁאֵלוֹת רִאשוֹנִיוֹת בְּסְקָאָלָה וּתשובוֹתֶיהָ". נִדְבֹּר עַל כְּמָה שְׁאֵלוֹת מִתְקַדְּמוֹת בְּסְקָאָלָה וּתשובוֹתֶיהָ בְּפֹסטִים הַבָּאִים שֶלִּי. בִּבְקָשָׁה, הוֹסִיפוּ תגובה אִם אַהֲבָתֶם אֶת הַפּוֹסְט שֶׁלִּי אוֹ יֵשׁ לָכֶם שְׁאֵלוֹת/הֶעָרוֹת.
Source:
https://www.digitalocean.com/community/tutorials/scala-interview-questions