الألغاز Kotlin ، المجلد. 2: مجموعة جديدة من الألغاز



هل يمكن أن تتنبأ بمدى تصرف كود Kotlin؟ هل ستجمع ما سينتج ولماذا؟

بغض النظر عن مدى جودة لغة البرمجة ، يمكن أن يلقي بحيث تظل فقط خدش الجزء الخلفي من الرأس. Kotlin ليست استثناء - إنها تحتوي أيضًا على ألغاز ، حتى عندما يكون هناك جزء قصير جدًا من الكود لديه سلوك غير متوقع.

مرة أخرى في عام 2017 ، نشرنا على Habré مجموعة مختارة من هؤلاء الألغاز من antonkeks Anton Keks . وقام بعد ذلك بأداء معنا على Mobius مع الاختيار الثاني ، وقمنا أيضًا بترجمته من أجل Habr إلى طريقة عرض نص ، مع إخفاء الإجابات الصحيحة تحت المفسدين.

نرفق أيضًا تسجيل الفيديو للكلام ، إذا ظهر شيء غير مفهوم في النص ، فيمكنك أيضًا الاتصال بها.


يستهدف النصف الأول من الألغاز أولئك الذين ليسوا على دراية بكوتلين. النصف الثاني هو لمطوري Kotlin المتشددين. سنبدأ كل شيء على Kotlin 1.3 ، حتى مع تمكين الوضع التدريجي. أكواد مصدر اللغز موجودة على جيثب . كل من يأتي بأفكار جديدة ، أرسل طلبات السحب.

المبزل رقم 1


fun hello(): Boolean { println(print(″Hello″) == print(″World″) == return false) } hello() 

أمامنا هي وظيفة مرحبا بسيطة ، فإنه يعمل عدة الطباعة. ونطلق هذه الوظيفة نفسها. سؤال بسيط لرفع تردد التشغيل: ما الذي يجب طباعته؟

أ) HelloWorld
ب) HelloWorldfalse
ج) HelloWorldtrue
د) لم يتم تجميعها

الإجابة الصحيحة


الخيار الأول كان صحيحا. يتم تشغيل المقارنة بعد أن بدأت كلتا الطبعتين بالفعل ، لا يمكن أن تبدأ قبل ذلك. لماذا يتم تجميع هذه الشفرة على الإطلاق؟ أي وظيفة بخلاف عودة لا شيء إرجاع شيء. نظرًا لأن كل شيء في Kotlin تعبير ، فإن العودة هي أيضًا تعبير. نوع المرتجعات هو لا شيء ، بل يتم إرساله إلى أي نوع ، بحيث يمكنك مقارنة مثل هذا. وحدة طباعة المرتجعات ، بحيث يمكن مقارنة الوحدة بـ Nothing أي عدد من المرات ، وكل شيء يعمل بشكل رائع.

عدد المبزل 2


 fun printInt(n: Int) { println(n) } printInt(-2_147_483_648.inc()) 

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

كل شيء يبدو بسيطا هنا. Kotlin لديه وظائف تمديد كبيرة مثل .inc () لزيادة. يمكننا أن نسميها على Int ، ويمكننا طباعة النتيجة. ماذا سيحدث؟

أ) -2147483647
ب) -2147483649
ج) 2147483647
د) لا شيء مما سبق

إطلاق!


كما تظهر رسالة الخطأ ، ها هي مشكلة Long. ولكن لماذا طويلة؟

وظائف التمديد لها الأولوية ، ويقوم المترجم أولاً بتشغيل inc () ، ثم عامل التشغيل ناقص. إذا تمت إزالة inc () ، فسيكون ذلك Int ، وسيعمل كل شيء. لكن inc () ، بدءًا من الأولى ، تتحول 2_147_483_648 إلى Long ، لأن هذا الرقم بدون ناقص لم يعد صالحًا. اتضح منذ فترة طويلة ، وعندها فقط يسمى الطرح. لم يعد بالإمكان تمرير كل هذا إلى وظيفة printInt () ، لأنه يتطلب Int.

إذا قمنا بتغيير مكالمة printInt إلى طباعة عادية ، والتي يمكن أن تقبل Long ، فسيكون الخيار الثاني صحيحًا.



ونحن نرى أن هذا هو في الواقع طويل. حذار من هذا: لا يمكن تشغيل جميع قطع الألغاز في الكود الحقيقي ، ولكن هذا ممكن.

المبزل رقم 3


 var x: UInt = 0u println(x--.toInt()) println(--x) 

في Kotlin 1.3 جاء ميزات جديدة رائعة. بالإضافة إلى النسخة النهائية من corutin ، نحن
الآن لديها أخيرا أرقام غير موقعة. يعد ذلك ضروريًا ، خاصةً إذا كنت تكتب نوعًا من رمز الشبكة.

حاليًا بالنسبة للحرفيات ، هناك حرف خاص u ، يمكننا تحديد الثوابت ، كما يمكننا في المثال ، التناقص x والتحول إلى Int. أذكرك أن كثافة العمليات على دراية بنا.

ماذا سيحدث؟

أ) -1 4294967294
ب) 0 4294967294
ج) 0 -2
د) لم يتم تجميعها

4294967294 هو العدد الأقصى 32 بت الذي يمكن الحصول عليه.

إطلاق!


الخيار الصحيح ب.

هنا ، كما في الإصدار السابق: أولاً ، يتم استدعاء toInt () على x ، وعندها فقط يتناقص. يتم عرض نتيجة التنازل غير الموقعة ، وهذا هو الحد الأقصى من unsignedInt.

الشيء الأكثر إثارة للاهتمام هو أنه إذا كتبت مثل هذا ، فلن يتم تجميع الشفرة:

 println(x--.toInt()) println(--x.toInt()) 

بالنسبة لي ، من الغريب أن الخط الأول يعمل ، والثاني - لا ، هذا غير منطقي.

وفي الإصدار التجريبي ، سيكون الخيار الصحيح هو C ، ويتم ذلك بشكل جيد في JetBrains الذي يعمل على إصلاح الخلل قبل إصدار الإصدار النهائي.

عدد المبزل 4


 val cells = arrayOf(arrayOf(1, 1, 1), arrayOf(0, 1, 1), arrayOf(1, 0, 1)) var neighbors = cells[0][0] + cells[0][1] + cells[0][2] + cells[1][0] + cells[1][2] + cells[2][0] + cells[2][1] + cells[2][2] print(neighbors) 

واجهنا هذه الحالة في رمز حقيقي. فعلنا في Codeborne Coding Dojo ، ونفذناه معًا على لعبة Kotlin Game of Life . كما ترون ، أنها ليست مريحة للغاية للعمل مع صفائف متعددة المستويات في Kotlin.

في Game of Life ، جزء مهم من الخوارزمية هو تحديد عدد الجيران للخلية. جميع الأطفال الصغار هم من الجيران ، ويعتمد ذلك على ما إذا كانت الخلية تعيش أو تموت. في هذا الكود ، يمكنك أن تعد هذه الأشياء وتفترض ما يحدث.

أ) 6
ب) 3
ج) 2
د) لم يتم تجميعها

لنرى


الجواب الصحيح هو 3.

والحقيقة هي أن علامة الجمع من السطر الأول يتم نقلها لأسفل ، ويعتقد Kotlin أن هذا هو unaryPlus (). نتيجة لذلك ، يتم تلخيص الخلايا الثلاث الأولى فقط. إذا كنا نرغب في كتابة هذا الرمز في عدة أسطر ، نحتاج إلى تحريك علامة الجمع.

هذا هو آخر من "الألغاز السيئة". تذكر ، في Kotlin ، لست بحاجة إلى نقل العبارة إلى سطر جديد ، وإلا فقد تعتبرها غير متحيزة.



لم أر مواقف تحتاج فيها unaryPlus في الكود الحقيقي باستثناء DSL. هذا موضوع غريب جدا.

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

ولكن هناك لغة جافا سكريبت رائعة جدًا لا يمكنك من خلالها كتابة فواصل منقوطة ، وسيظل هذا الرمز يعمل بشكل صحيح.

المبهر رقم 5


 val x: Int? = 2 val y: Int = 3 val sum = x?:0 + y println(sum) 

يظهر هذا اللغز من قبل المتحدث باسم KotlinConf توماس نيلد.

Kotlin لديه ميزة أنواع nullable كبيرة. لدينا x nullable ، ويمكننا تحويله ، إذا اتضح أنه لاغٍ ، من خلال مشغل Elvis إلى قيمة عادية.

ماذا سيحدث؟

أ) 3
ب) 5
ج) 2
د) 0

إطلاق!


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

 val sum = x ?: 0+y 

يشير التنسيق بالفعل إلى أن 0 + y يبدأ أولاً ، وعندها فقط x؟:. لذلك ، بالطبع ، لا يزال 2 ، لأن X هو اثنان ، أنها ليست خالية.

المبزل رقم 6


 data class Recipe (var name: String? = null, var hops: List<Hops> = emptyList() ) data class Hops(var kind: String? = null, var atMinute: Int = 0, var grams: Int = 0) fun beer(build: Recipe.() -> Unit) = Recipe().apply(build) fun Recipe.hops(build: Hops.() -> Unit) { hops += Hops().apply(build) } val recipe = beer { name = ″Simple IPA″ hops { name = ″Cascade″ grams = 100 atMinute = 15 } } 

عندما اتصلوا بي هنا ، وعدوني بصنع البيرة. سأبحث عنه الليلة ، لم أره بعد. Kotlin لديه موضوع كبير - بناة. مع أربعة أسطر من التعليمات البرمجية ، نكتب DSL الخاص بنا ثم ننشئها من خلال البناة.

نقوم أولاً بإنشاء IPA ، ونضيف قفزات تسمى Cascade ، 100 جرام في الدقيقة 15 من الغليان ، ثم نطبع هذه الوصفة. ماذا فعلنا؟

أ) الوصفة (الاسم = IPA البسيط ، القفزات = [القفزات (الاسم = Cascade ، atMinute = 15 ، غرام = 100)])
ب) IllegalArgumentException
ج) لم يتم تجميعها
د) لا شيء مما سبق

إطلاق!


لقد حصلنا على شيء مشابه للبيرة الحرفية ، ولكن لا توجد قفزات فيه ، فقد اختفى. أرادوا الحصول على IPA ، لكنهم حصلوا على بحر البلطيق 7.

هذا هو المكان الذي حدث صدام التسمية. يُسمى الحقل في القفزات بالفعل النوع ، وفي اسم السطر = ″ Cascade ″ نستخدم الاسم ، والذي يتم تخزينه مؤقتًا مع اسم الوصفة.

يمكننا إنشاء تعليق توضيحي خاص بـ BeerLang وتسجيله كجزء من BeerLang DSL. نحن نحاول الآن تشغيل هذا الرمز ، ويجب ألا يتم تجميعه معنا.



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



المبهر رقم 7



 fun f(x: Boolean) { when (x) { x == true -> println(″$x TRUE″) x == false -> println(″$x FALSE″) } } f(true) f(false) 

هذا اللغز هو أحد موظفي JetBrains. Kotlin لديه ميزة عندما. إنه لجميع المناسبات ، فهو يسمح لك بكتابة كود رائع ، وغالبًا ما يستخدم مع فئات مختومة لتصميم API.

في هذه الحالة ، لدينا دالة f () تأخذ منطقية وتطبع شيئًا حسب الصواب والخطأ.

ماذا سيحدث؟

أ) صحيح حقيقي ؛ خطأ كاذب
ب) صحيح صحيح ؛ صحيح كاذب
ج) خطأ صحيح ؛ خطأ كاذب
د) لا شيء مما سبق

لنرى


لماذا هذا أولاً ، نحسب التعبير x == true: على سبيل المثال ، في الحالة الأولى ، سيكون true == true ، وهو ما يعني true. ثم هناك أيضًا مقارنة بالنمط الذي مررنا به عند.

وعندما يتم تعيين x على "خطأ" ، فإن تقييم x == true سيعطينا خطأ ، ومع ذلك ، فإن العينة ستكون خاطئة أيضًا - لذلك فإن المثال سيطابق العينة.

هناك طريقتان لإصلاح هذا الرمز ، أحدهما إزالة "x ==" في كلتا الحالتين:

 fun f(x: Boolean) { when (x) { true -> println(″$x TRUE″) false -> println(″$x FALSE″) } } f(true) f(false) 

الخيار الثاني هو إزالة (س) بعد متى. عندما يعمل مع أي شروط ، ومن ثم لن تتطابق مع العينة.

 fun f(x: Boolean) { when { x == true -> println(″$x TRUE″) x == false -> println(″$x FALSE″) } } f(true) f(false) 


البازل رقم 8


 abstract class NullSafeLang { abstract val name: String val logo = name[0].toUpperCase() } class Kotlin : NullSafeLang() { override val name = ″Kotlin″ } print(Kotlin().logo) 

تم تسويق Kotlin كلغة "آمنة خالية". تخيل أن لدينا فئة مجردة ، لها اسم ، وأيضًا خاصية تُرجع شعار هذه اللغة: الحرف الأول من الاسم ، فقط في حالة ، جعل رأس المال (فجأة تم نسيان تكوين رأس المال الأولي).

نظرًا لأن اللغة غير آمنة ، سنقوم بتغيير الاسم وربما نحصل على الشعار الصحيح ، وهو حرف واحد. ما الذي حصلنا عليه حقًا؟

أ) ك
ب) NullPointerException
ج) IllegalStateException
د) لم يتم تجميعها

إطلاق!


لقد حصلنا على NullPointerException ، والذي يجب ألا نتلقاه. المشكلة هي أن مُنشئ الطبقة الفائقة يُسمى أولاً ، ويحاول الرمز تهيئة شعار الخاصية وأخذ اسم شار من الصفر ، وعند هذه النقطة يكون الاسم خاليًا ، لذلك يحدث NullPointerException.

أفضل طريقة لإصلاح ذلك هي القيام بذلك:

 class Kotlin : NullSafeLang() { override val name get() = ″Kotlin″ } 

إذا قمنا بتشغيل هذا الرمز ، فسوف نحصل على "K" الآن ستدعو الفئة الأساسية مُنشئ الفئة الأساسية ، وستتصل فعليًا باسم getter وستحصل على Kotlin.

تعد خاصية ميزة رائعة في Kotlin ، ولكن عليك أن تكون حذراً للغاية عند تجاوز الخصائص ، لأنه من السهل جدًا نسيانها أو ارتكاب خطأ أو ضمان حدوث خطأ.


البازل رقم 9


 val result = mutableListOf<() -> Unit>() var i = 0 for (j in 1..3) { i++ result += { print(″$i, $j; ″) } } result.forEach { it() } 

هناك mutableList بعض الأشياء المخيفة. إذا كان يذكرك بـ Scala ، فهو ليس عبثًا ، لأنه يبدو بالفعل. هناك قائمة lambd ، نأخذ عدادين - I و j ، نزيد ونعمل شيئًا معهم. ماذا سيحدث؟

أ) 1 1 ؛ 2 2 3 3
ب) 1 3 ؛ 2 3 3 3
ج) 3 1 ؛ 3 2 3 3
د) لا شيء مما سبق

لنركض


نحصل على 3 1 ؛ 3 2 3 3. يحدث هذا لأنني متغير ، وسوف تحتفظ بقيمته حتى نهاية الوظيفة. ويتم تمرير j بالقيمة.

إذا بدلاً من var i = 0 سيكون هناك val i = 0 ، هذا لن ينجح ، لكن بعد ذلك لم نتمكن من زيادة المتغير.

هنا في Kotlin نستخدم الإغلاق ، هذه الميزة ليست في Java. إنه رائع للغاية ، لكن يمكن أن يعضنا إذا لم نستخدم قيمة i على الفور ، ولكن نقلها إلى lambda ، التي تبدأ لاحقًا وترى القيمة الأخيرة لهذا المتغير. يتم تمرير j بالقيمة ، نظرًا لأن المتغيرات في شرط الحلقة - هي نفس القيمة ، لم تعد تغير قيمتها.

في JavaScript ، سيكون الجواب "3 3؛ 3 3 3 3 "، لأنه لا يوجد شيء ينتقل بالقيمة.


البازل رقم 10


 fun foo(a:Boolean, b: Boolean) = print(″$a, $b″) val a = 1 val b = 2 val c = 3 val d = 4 foo(c < a, b > d) 

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

أ) صحيح ، صحيح
ب) كاذبة ، كاذبة
ج) لاغية ، لاغية
د) لم يتم تجميعها

نطلق


لا جمعت.

المشكلة هي أن المترجم يعتقد أن هذا يشبه المعلمات العامة: مع <a ، b>. على الرغم من أن "c" ليس فئة ، إلا أنه من غير الواضح لماذا يجب أن تحتوي على معلمات عامة.

إذا كانت الشفرة هكذا ، فستعمل بشكل جيد:

 foo(c > a, b > d) 

يبدو لي أن هذا خطأ في المترجم. لكن عندما أذهب إلى Andrei Breslav مع أي من هؤلاء الألغاز ، يقول "هذا لأن المحلل اللغوي مثل هذا ، فإنهم لا يريدون أن يكون بطيئًا للغاية." بشكل عام ، يجد دائمًا سبب لذلك.

لسوء الحظ ، هذا صحيح. قال إنهم لن يصلحوا ، لأن المحلل اللغوي في
Kotlin لا يعرف دلالات حتى الآن. يحدث التحليل أولاً ثم يقوم بتمريره إلى مكون برنامج التحويل البرمجي آخر. لسوء الحظ ، ربما سيبقى هذا كذلك. لذلك لا تكتب اثنين من هذه الأقواس الزاوية وأي رمز في منتصف!

المبزل رقم 11


 data class Container(val name: String, private val items: List<Int>) : List<Int> by items val (name, items) = Container(″Kotlin″, listOf(1, 2, 3)) println(″Hello $name, $items″) 

المندوب ميزة رائعة في Kotlin. بالمناسبة ، يقول Andrei Breslav أن هذه ميزة يزيلها بكل سرور من اللغة ، لم يعد يحبها. الآن ، ربما ، سوف نعرف لماذا! وقال أيضًا إن الأشياء المصاحبة قبيحة.

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

ثم نستخدم ميزة أخرى رائعة - التدمير. نحن "ندمر" عناصر الاسم والعناصر من الحاوية ونعرضها على الشاشة. يبدو أن كل شيء بسيط وواضح. ماذا سيحدث؟

أ) Hello Kotlin ، [1 ، 2 ، 3]
ب) مرحبا Kotlin ، 1
ج) مرحبا 1 ، 2
د) مرحبا Kotlin ، 2

نطلق


الخيار الأكثر غموضا هو د. اتضح أن يكون صحيحا. كما اتضح ، تختفي العناصر ببساطة من مجموعة العناصر ، وليس من البداية أو من النهاية ، ولكن من الوسط فقط. لماذا؟

مشكلة التدمير هي أنه بسبب التفويض ، كل المجموعات في Kotlin هي أيضًا
لدينا خيارهم الخاص من التدمير. يمكنني كتابة val (I ، j) = listOf (1 ، 2) ، والحصول على هذه 1 و 2 في المتغيرات ، وهذا هو ، نفذت القائمة وظائف component1 () و
component2 ().

تحتوي فئة البيانات أيضًا على المكون 1 () والمكون 2 (). ولكن نظرًا لأن المكون الثاني في هذه الحالة خاص ، فإن العنصر العام في القائمة يفوز ، لذلك يتم أخذ العنصر الثاني من القائمة ، ونصل إلى هنا 2. والمبدأ الأخلاقي بسيط للغاية: لا تفعل ذلك ، لا تفعل ذلك.

المبزل رقم 12


اللغز القادم هو مخيف جدا. هذا شخص خاضع مرتبط بطريقة ما بـ Kotlin ، لذلك فهو يعرف ما يكتب.

 fun <T> Any?.asGeneric() = this as? T 42.asGeneric<Nothing>()!!!! val a = if (true) 87 println(a) 

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

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

ثم نفعل إذا (صحيح) ، ثم أنا شخصياً لا أفهم أي شيء ... دعونا نختار على الفور ما يحدث.

87)
ب) Kotlin.Unit
ج) ClassCastException
د) لم يتم تجميعها

مشاهدة


من الصعب للغاية تقديم تفسير منطقي. على الأرجح ، ترجع الوحدة هنا إلى حقيقة أنه لا يوجد شيء آخر للدفع إلى هناك. هذا رمز غير صالح ، لكنه يعمل لأننا لم نستخدم أي شيء. لقد حملنا شيئًا إلى Nothing ، وهذا نوع خاص يخبر المترجم أنه يجب ألا يظهر مثيل من هذا النوع أبدًا. يعرف المترجم أنه إذا كانت هناك إمكانية لـ Nothing ، وهو أمر مستحيل بحكم التعريف ، فلا يمكنك التحقق أكثر من ذلك ، فهذا موقف مستحيل.

على الأرجح ، هذا خطأ في المحول البرمجي ، حتى أن فريق JetBrains قال إنه ربما سيتم إصلاح هذا الخطأ يومًا ما ، فهذا ليس بالأولوية القصوى. الحيلة هي أننا خدعت المترجم هنا بسبب هذا المدلى بها. إذا قمت بإزالة السطر 42.asGeneric <Nothing> () !!! والتوقف عن الغش ، وسوف تتوقف التعليمات البرمجية. وإذا غادرنا ، فإن المترجم يصبح مجنونًا ، ويعتقد أن هذا تعبير مستحيل ، والأشياء التي يحصل عليها هناك.

أنا أفهم ذلك. ربما شخص ما سوف يفسره يوما ما بشكل أفضل.


البازل رقم 13


لدينا ميزة مثيرة للاهتمام للغاية. يمكنك استخدام حقن التبعية ، أو يمكنك الاستغناء عنه ، وجعل النغمات الفردية من خلال الكائن وتشغيل البرنامج باردًا. لماذا تحتاج كوين ، خنجر أو شيء من هذا؟ الاختبار ، ومع ذلك ، سيكون صعبا.

 open class A(val x: Any?) { override fun toString() = javaClass.simpleName } object B : A(C) object C : A(B) println(Bx) println(Cx) 

لدينا فئة A مفتوحة للميراث ، وهي تأخذ شيئًا من داخلها ، ونقوم بإنشاء كائنين ، المفرد ، B و C ، كلاهما يرثان من A ونمر بعضنا البعض هناك. وهذا هو ، يتم تشكيل دورة ممتازة. ثم نطبع ما حصل عليه B و C.

أ) لاغ لاغية
ب) ج. لاغية
ج) ExceptionInInitializerError
د) لم يتم تجميعها

نطلق


الخيار الصحيح هو C ؛ لاغية

قد يظن المرء أنه عندما تتم تهيئة الكائن الأول ، فإن الثاني ليس هناك بعد. لكن عندما نستنتج هذا ، فإن C تفتقر إلى B. وهذا هو ، يتم الحصول على الترتيب العكسي: لسبب ما ، قرر المترجم تهيئة C أولاً ، ثم قام بتهيئة B مع C. يبدو غير منطقي ، سيكون منطقيًا ، على العكس من ذلك ، لاغٍ ؛ ب.

لكن المحول البرمجي حاول أن يفعل شيئًا ، لم ينجح ، لقد تركه فارغًا وقرر عدم إلقاء شيء علينا. يمكن أن يكون مثل هذا أيضا

إن وجدت؟ في نوع المعلمة ، وإزالة؟ ، فإنه لن يعمل.



يمكننا أن نقول جيدا للمترجم أنه عندما تم حل null ، حاول ، لكنه فشل ، ولكن ماذا؟ لا ، إنه يرمي لنا استثناء أنه من المستحيل إجراء دورة.

المبزل №14


الإصدار 1.3 صدر coroutines كبيرة جديدة في Kotlin. لقد فكرت لفترة طويلة كيف أتوصل إلى ألغاز حول corutin ، حتى يتمكن شخص ما من فهم ذلك. أعتقد أن بعض التعليمات البرمجية مع coroutines هو اللغز بالنسبة لبعض الناس.

في 1.3 ، تم تغيير بعض أسماء الوظائف التي كانت في 1.2 في واجهة برمجة التطبيقات التجريبية. على سبيل المثال ، تتم إعادة تسمية buildSequence () لتسلسل ببساطة (). وهذا يعني أنه يمكننا عمل تسلسلات ممتازة باستخدام دالة الإنتاجية ، حلقات لا نهائية ، ومن ثم يمكننا محاولة الحصول على شيء من هذا التسلسل.

 package coroutines.yieldNoOne val x = sequence { var n = 0 while (true) yield(n++) } println(x.take(3)) 

قالوا مع coroutines أن جميع البدائل الرائعة الموجودة بلغات أخرى ، مثل المحصول ، يمكن أن يتم القيام بها كوظائف مكتبة ، لأن العائد هو وظيفة تعليق يمكن إيقافها.

ماذا سيحدث؟

أ) [1 ، 2 ، 3]
ب) [0 ، 1 ، 2]
ج) حلقة لانهائية
د) لا شيء مما سبق

إطلاق!


الخيار الصحيح هو الأخير.

التسلسل هو كونك كسول ، وعندما نتشبث به ، فهو كسول أيضًا. ولكن إذا أضفت إلى القائمة ، فسيتم طباعتها بالفعل [0 ، 1 ، 2].

لا ترتبط الإجابة الصحيحة بالكوروتينات على الإطلاق. Coroutines حقا العمل ، فهي سهلة الاستخدام. للحصول على وظيفة التسلسل والعائد ، لن تحتاج حتى إلى توصيل مكتبة بالكوروتينات ، كل شيء موجود بالفعل في المكتبة القياسية.

المبخر №15


هذا اللغز مهزوم أيضًا من قبل المطور من JetBrains. هناك مثل هذا كود الجهنمية:

 val whatAmI = {->}.fun Function<*>.(){}() println(whatAmI) 

عندما رأيته للمرة الأولى ، خلال KotlinConf ، لم أستطع النوم ، حاولت أن أفهم ما كان عليه. يمكن كتابة هذه الشفرة الخفية في Kotlin ، لذا إذا اعتقد أحدهم أن Scalaz كان مخيفًا ، فمن الممكن أيضًا في Kotlin.

لنخمن:

أ) Kotlin.Unit
ب) Kotlin. لا شيء
ج) لم يتم تجميعها
د) لا شيء مما سبق

لنركض


وصلنا الوحدة التي جاءت من أي مكان.

لماذا؟ أولاً نقوم بتعيين متغير lambda: {->} - هذا رمز صالح ، يمكنك كتابة lambda فارغة. لا يوجد لديه المعلمات ، فإنه لا يعود شيئا. وفقا لذلك ، فإنه يعود وحدة.

نقوم بتعيين lambda للمتغير وكتابة ملحق على الفور إلى هذا lambda ، ثم تشغيله. في الواقع ، سوف تقوم ببساطة بحجز Kotlin.Unit.

ثم في هذا لامدا يمكنك كتابة وظيفة التمديد:

 .fun Function<*>.(){} 

يتم الإعلان عنها على نوع الوظيفة <*> ، وما لدينا في الأعلى مناسب أيضًا لها. في الواقع هي وظيفة <الوحدة> ، لكنني لم أكتب وحدة أنه لم يكن واضحا. هل تعرف كيف تعمل النجمة في Kotlin؟ , Java. , .

, Unit {}, , void-. , , . -, — .

. , Kotlin — . iOS- , , Kotlin !
Mobius, : Mobius 22-23 . Kotlin — «Coroutining Android Apps» . ( Android, iOS), — , 1 .

: , — 6 .

Source: https://habr.com/ru/post/ar440974/


All Articles