Kotlin یک زبان برنامه نویسی است که به طور گسترده توسط توسعه دهندگان اندروید در همه جا استفاده می شود. این موضوع بهعنوان یک دوره تصادف کاتلین عمل میکند تا شما را به سرعت راهاندازی کند.
اعلام متغیر
کاتلین از دو کلمه کلیدی مختلف برای اعلام متغیرها استفاده می کند: val
و var
.
-
val
برای متغیری استفاده کنید که مقدار آن هرگز تغییر نمی کند. شما نمی توانید مقداری را به متغیری که با استفاده ازval
اعلان شده است دوباره اختصاص دهید. - برای متغیری که مقدار آن می تواند تغییر کند از
var
استفاده کنید.
در مثال زیر، count
یک متغیر از نوع Int
است که مقدار اولیه 10
به آن اختصاص داده شده است:
var count: Int = 10
Int
نوعی است که یک عدد صحیح را نشان می دهد، یکی از انواع عددی متعددی که می توان در Kotlin نمایش داد. مشابه سایر زبانها، میتوانید بسته به دادههای عددی خود از Byte
، Short
، Long
، Float
و Double
نیز استفاده کنید.
کلمه کلیدی var
به این معنی است که شما می توانید مقادیر را برای count
مجدد در صورت نیاز اختصاص دهید. به عنوان مثال، می توانید مقدار count
را از 10
به 15
تغییر دهید:
var count: Int = 10
count = 15
با این حال، برخی از مقادیر قرار نیست تغییر کنند. String
به نام languageName
در نظر بگیرید. اگر می خواهید اطمینان حاصل کنید که languageName
همیشه مقدار "Kotlin" را در خود دارد، می توانید languageName
با استفاده از کلمه کلیدی val
اعلام کنید:
val languageName: String = "Kotlin"
این کلمات کلیدی به شما این امکان را میدهند که در مورد آنچه میتوان تغییر داد به صراحت صحبت کنید. در صورت نیاز از آنها به نفع خود استفاده کنید. اگر یک مرجع متغیر باید قابل تخصیص مجدد باشد، آن را به عنوان var
اعلام کنید. در غیر این صورت از val
استفاده کنید.
استنتاج تایپ کنید
در ادامه مثال قبلی، وقتی یک مقدار اولیه را به languageName
اختصاص میدهید، کامپایلر Kotlin میتواند نوع را بر اساس نوع مقدار تخصیص یافته استنتاج کند.
از آنجایی که مقدار "Kotlin"
از نوع String
است، کامپایلر استنباط می کند که languageName
نیز یک String
است. توجه داشته باشید که کاتلین یک زبان استاتیکی است. این بدان معنی است که نوع در زمان کامپایل حل می شود و هرگز تغییر نمی کند.
در مثال زیر، languageName
به عنوان یک String
استنباط شده است، بنابراین نمیتوانید تابعهایی را که بخشی از کلاس String
نیستند فراخوانی کنید:
val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()
// Fails to compile
languageName.inc()
toUpperCase()
تابعی است که فقط روی متغیرهایی از نوع String
فراخوانی می شود. از آنجایی که کامپایلر Kotlin languageName
به عنوان یک String
استنباط کرده است، می توانید با خیال راحت toUpperCase()
را فراخوانی کنید. با این حال، inc()
یک تابع عملگر Int
است، بنابراین نمی توان آن را روی یک String
فراخوانی کرد. رویکرد کاتلین برای استنتاج نوع به شما هم مختصر و هم ایمنی نوع می دهد.
ایمنی پوچ
در برخی از زبان ها، یک متغیر نوع مرجع را می توان بدون ارائه یک مقدار صریح اولیه اعلام کرد. در این موارد، متغیرها معمولا حاوی یک مقدار تهی هستند. متغیرهای Kotlin به طور پیش فرض نمی توانند مقادیر تهی را نگه دارند. این به این معنی است که قطعه زیر نامعتبر است:
// Fails to compile
val languageName: String = null
برای اینکه یک متغیر مقدار تهی داشته باشد، باید از نوع nullable باشد. شما می توانید با پسوند نوع آن با ?
، همانطور که در مثال زیر نشان داده شده است:
val languageName: String? = null
با String?
تایپ کنید، می توانید یک مقدار String
یا null
به languageName
اختصاص دهید.
شما باید متغیرهای nullable را با دقت مدیریت کنید یا در معرض خطر NullPointerException
مخوف باشید. به عنوان مثال، در جاوا، اگر بخواهید متدی را بر روی یک مقدار تهی فراخوانی کنید، برنامه شما از کار می افتد.
کاتلین تعدادی مکانیسم برای کار ایمن با متغیرهای پوچ ارائه می کند. برای اطلاعات بیشتر، الگوهای رایج کاتلین را در اندروید ببینید: پوچپذیری .
شرایط
کاتلین چندین مکانیسم برای اجرای منطق شرطی دارد. رایج ترین آنها عبارت if-else است. اگر عبارتی که در پرانتز در کنار یک کلمه کلیدی if
قرار گرفته باشد، به true
ارزیابی شود، کد درون آن شاخه (یعنی کد بلافاصله پس از آن که در پرانتز پیچیده شده است) اجرا می شود. در غیر این صورت کد داخل شاخه else
اجرا می شود.
if (count == 42) {
println("I have the answer.")
} else {
println("The answer eludes me.")
}
می توانید چندین شرط را با استفاده else if
نشان دهید. همانطور که در مثال زیر نشان داده شده است، این به شما امکان میدهد منطق ریزتر و پیچیدهتری را در یک دستور شرطی نشان دهید:
if (count == 42) {
println("I have the answer.")
} else if (count > 35) {
println("The answer is close.")
} else {
println("The answer eludes me.")
}
عبارات شرطی برای نشان دادن منطق حالتی مفید هستند، اما ممکن است متوجه شوید که هنگام نوشتن آنها، خود را تکرار می کنید. در مثال بالا، شما به سادگی یک String
را در هر شاخه چاپ می کنید. برای جلوگیری از این تکرار، کاتلین عبارات شرطی را ارائه می دهد. نمونه آخر را می توان به صورت زیر بازنویسی کرد:
val answerString: String = if (count == 42) {
"I have the answer."
} else if (count > 35) {
"The answer is close."
} else {
"The answer eludes me."
}
println(answerString)
به طور ضمنی، هر شاخه شرطی نتیجه عبارت را در خط نهایی خود برمی گرداند، بنابراین نیازی به استفاده از کلمه کلیدی return
ندارید. چون نتیجه هر سه شاخه از نوع String
است، نتیجه عبارت if-else نیز از نوع String
است. در این مثال، answerString
یک مقدار اولیه از نتیجه عبارت if-else اختصاص داده شده است. استنتاج نوع را می توان برای حذف اعلان نوع صریح برای answerString
استفاده کرد، اما اغلب ایده خوبی است که آن را برای وضوح اضافه کنید.
همانطور که در مثال زیر نشان داده شده است، همانطور که پیچیدگی دستور شرطی شما افزایش می یابد، ممکن است در نظر داشته باشید که عبارت if-else خود را با عبارت When جایگزین کنید:
val answerString = when {
count == 42 -> "I have the answer."
count > 35 -> "The answer is close."
else -> "The answer eludes me."
}
println(answerString)
هر شاخه در عبارت when
با یک شرط، یک فلش ( ->
) و یک نتیجه نشان داده می شود. اگر شرط سمت چپ فلش درست باشد، نتیجه عبارت سمت راست برگردانده می شود. توجه داشته باشید که اجرا از یک شاخه به شاخه دیگر نمی افتد. کد در مثال عبارت when
از نظر عملکردی با مثال قبلی برابر است اما احتمالاً خواندن آن آسانتر است.
شرایط شرطی کاتلین یکی از ویژگی های قدرتمندتر آن، ریخته گری هوشمند را برجسته می کند. به جای استفاده از عملگر ایمن فراخوانی یا عملگر ادعای غیر تهی برای کار با مقادیر تهی، می توانید در عوض بررسی کنید که آیا یک متغیر دارای ارجاع به مقدار تهی با استفاده از یک دستور شرطی است، همانطور که در مثال زیر نشان داده شده است:
val languageName: String? = null
if (languageName != null) {
// No need to write languageName?.toUpperCase()
println(languageName.toUpperCase())
}
در شاخه شرطی، languageName
ممکن است غیرقابل تهی در نظر گرفته شود. Kotlin به اندازه کافی هوشمند است که تشخیص دهد شرط اجرای شاخه این است که languageName
مقدار تهی نداشته باشد، بنابراین مجبور نیستید languageName
در آن شاخه به عنوان nullable در نظر بگیرید. این ریخته گری هوشمند برای چک های پوچ، چک های نوع یا هر شرایطی که قرارداد را برآورده می کند، کار می کند.
توابع
می توانید یک یا چند عبارت را در یک تابع گروه بندی کنید. به جای تکرار همان سری عبارات هر بار که به نتیجه نیاز دارید، می توانید عبارات را در یک تابع بپیچید و به جای آن تابع را فراخوانی کنید.
برای اعلام یک تابع، از کلمه کلیدی fun
و به دنبال آن نام تابع استفاده کنید. در مرحله بعد، انواع ورودی هایی را که تابع شما می گیرد، در صورت وجود، تعریف کنید و نوع خروجی را که برمی گرداند، اعلام کنید. بدنه یک تابع جایی است که شما عباراتی را تعریف می کنید که هنگام فراخوانی تابع شما فراخوانی می شوند.
با تکیه بر نمونه های قبلی، در اینجا یک تابع کامل Kotlin آمده است:
fun generateAnswerString(): String {
val answerString = if (count == 42) {
"I have the answer."
} else {
"The answer eludes me"
}
return answerString
}
تابع موجود در مثال بالا نام generateAnswerString
دارد. هیچ ورودی نمی گیرد. خروجی آن از نوع String
است. برای فراخوانی یک تابع، از نام آن و به دنبال آن عملگر فراخوانی ( ()
) استفاده کنید. در مثال زیر، متغیر answerString
با نتیجه generateAnswerString()
مقداردهی اولیه می شود.
val answerString = generateAnswerString()
همانطور که در مثال زیر نشان داده شده است، توابع می توانند آرگومان ها را به عنوان ورودی دریافت کنند:
fun generateAnswerString(countThreshold: Int): String {
val answerString = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
return answerString
}
هنگام اعلان یک تابع، می توانید هر تعداد آرگومان و انواع آنها را مشخص کنید. در مثال بالا، generateAnswerString()
یک آرگومان به نام countThreshold
از نوع Int
می گیرد. در داخل تابع، می توانید با استفاده از نام آرگومان به آن مراجعه کنید.
هنگام فراخوانی این تابع، باید یک آرگومان در داخل پرانتز فراخوانی تابع قرار دهید:
val answerString = generateAnswerString(42)
ساده کردن اعلان های تابع
generateAnswerString()
یک تابع نسبتا ساده است. تابع یک متغیر را اعلام می کند و سپس بلافاصله برمی گردد. هنگامی که نتیجه یک عبارت واحد از یک تابع برگردانده می شود، می توانید با بازگرداندن مستقیم نتیجه عبارت if-else موجود در تابع، از اعلام یک متغیر محلی صرفنظر کنید، همانطور که در مثال زیر نشان داده شده است:
fun generateAnswerString(countThreshold: Int): String {
return if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
}
همچنین می توانید کلمه کلیدی بازگشت را با عملگر انتساب جایگزین کنید:
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
"I have the answer"
} else {
"The answer eludes me"
}
توابع ناشناس
هر تابعی نیاز به نام ندارد. برخی از توابع به طور مستقیم با ورودی و خروجی آنها شناسایی می شوند. این توابع را توابع ناشناس می نامند. می توانید یک مرجع به یک تابع ناشناس نگه دارید، از این مرجع برای فراخوانی تابع ناشناس بعدا استفاده کنید. شما همچنین می توانید مانند سایر انواع مرجع، مرجع را در اطراف برنامه خود ارسال کنید.
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
مانند توابع نامگذاری شده، توابع ناشناس می توانند شامل هر تعداد عبارت باشند. مقدار بازگشتی تابع نتیجه عبارت نهایی است.
در مثال بالا، stringLengthFunc
حاوی یک مرجع به یک تابع ناشناس است که یک String
به عنوان ورودی می گیرد و طول String
ورودی را به عنوان خروجی از نوع Int
برمی گرداند. به همین دلیل، نوع تابع به صورت (String) -> Int
نشان داده می شود. با این حال، این کد تابع را فراخوانی نمی کند. برای بازیابی نتیجه تابع، باید آن را مانند تابعی با نام فراخوانی کنید. همانطور که در مثال زیر نشان داده شده است، هنگام فراخوانی stringLengthFunc
باید یک String
ارائه کنید:
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
val stringLength: Int = stringLengthFunc("Android")
توابع مرتبه بالاتر
یک تابع می تواند تابع دیگری را به عنوان آرگومان بگیرد. توابعی که از توابع دیگر به عنوان آرگومان استفاده می کنند ، توابع مرتبه بالاتر نامیده می شوند. این الگو برای برقراری ارتباط بین مؤلفهها به همان روشی که ممکن است از یک واسط برگشت تماس در جاوا استفاده کنید، مفید است.
در اینجا مثالی از یک تابع مرتبه بالاتر آورده شده است:
fun stringMapper(str: String, mapper: (String) -> Int): Int {
// Invoke function
return mapper(str)
}
تابع stringMapper()
یک String
به همراه تابعی می گیرد که مقدار Int
را از String
که شما به آن ارسال می کنید مشتق می کند.
همانطور که در مثال زیر نشان داده شده است String
میتوانید stringMapper()
را با ارسال یک String
و تابعی که پارامتر ورودی دیگر را برآورده میکند Int
فراخوانی کنید.
stringMapper("Android", { input ->
input.length
})
اگر تابع ناشناس آخرین پارامتر تعریف شده بر روی یک تابع باشد، می توانید آن را خارج از پرانتزهای مورد استفاده برای فراخوانی تابع ارسال کنید، همانطور که در مثال زیر نشان داده شده است:
stringMapper("Android") { input ->
input.length
}
توابع ناشناس را می توان در سراسر کتابخانه استاندارد Kotlin یافت. برای اطلاعات بیشتر، به توابع بالاتر و لامبدا مراجعه کنید.
کلاس ها
تمام انواع ذکر شده تا کنون در زبان برنامه نویسی کاتلین ساخته شده اند. اگر می خواهید نوع سفارشی خود را اضافه کنید، می توانید با استفاده از کلمه کلیدی class
یک کلاس تعریف کنید، همانطور که در مثال زیر نشان داده شده است:
class Car
خواص
کلاس ها حالت را با استفاده از ویژگی ها نشان می دهند. ویژگی یک متغیر در سطح کلاس است که می تواند شامل یک گیرنده، یک تنظیم کننده و یک فیلد پشتوانه باشد. از آنجایی که یک ماشین برای راندن به چرخ نیاز دارد، می توانید لیستی از اشیاء Wheel
را به عنوان ویژگی Car
اضافه کنید، همانطور که در مثال زیر نشان داده شده است:
class Car {
val wheels = listOf<Wheel>()
}
توجه داشته باشید که wheels
یک public val
است، به این معنی که wheels
از خارج از کلاس Car
قابل دسترسی هستند و نمیتوان آن را مجدداً اختصاص داد. اگر می خواهید نمونه ای از Car
را بدست آورید، ابتدا باید سازنده آن را فراخوانی کنید. از آنجا می توانید به هر یک از ویژگی های قابل دسترسی آن دسترسی داشته باشید.
val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car
اگر میخواهید چرخهای خود را سفارشی کنید، میتوانید یک سازنده سفارشی تعریف کنید که مشخص میکند خصوصیات کلاس شما چگونه مقداردهی اولیه میشوند:
class Car(val wheels: List<Wheel>)
در مثال بالا، سازنده کلاس یک List<Wheel>
به عنوان آرگومان سازنده می گیرد و از آن آرگومان برای مقداردهی اولیه ویژگی wheels
خود استفاده می کند.
توابع کلاس و کپسولاسیون
کلاس ها از توابع برای مدل سازی رفتار استفاده می کنند. توابع می توانند وضعیت را تغییر دهند و به شما کمک می کنند فقط داده هایی را که می خواهید در معرض نمایش قرار دهید در معرض دید قرار دهید. این کنترل دسترسی بخشی از یک مفهوم شی گرا بزرگتر است که به عنوان کپسوله سازی شناخته می شود.
در مثال زیر، ویژگی doorLock
از هر چیزی خارج از کلاس Car
خصوصی نگه داشته می شود. برای باز کردن قفل ماشین، باید تابع unlockDoor()
را که در یک کلید معتبر عبور می کند، فراخوانی کنید، همانطور که در مثال زیر نشان داده شده است:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
اگر می خواهید نحوه ارجاع یک ویژگی را سفارشی کنید، می توانید یک گیرنده و تنظیم کننده سفارشی ارائه دهید. برای مثال، اگر میخواهید گیرنده یک ویژگی را در معرض دید قرار دهید و دسترسی به تنظیمکننده آن را محدود کنید، میتوانید آن تنظیمکننده را به عنوان private
تعیین کنید:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
var gallonsOfFuelInTank: Int = 15
private set
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
با ترکیبی از ویژگی ها و توابع، می توانید کلاس هایی ایجاد کنید که انواع اشیاء را مدل می کنند.
قابلیت همکاری
یکی از مهم ترین ویژگی های کاتلین، قابلیت همکاری سیال آن با جاوا است. از آنجا که کد Kotlin به بایت کد JVM کامپایل می شود، کد Kotlin شما می تواند مستقیماً به کد جاوا و بالعکس فراخوانی کند. این بدان معناست که شما می توانید کتابخانه های جاوا موجود را مستقیماً از Kotlin استفاده کنید. علاوه بر این، اکثر API های اندروید به زبان جاوا نوشته شده اند و می توانید مستقیماً از Kotlin با آنها تماس بگیرید.
مراحل بعدی
کاتلین یک زبان منعطف و عملگرا با پشتیبانی و حرکت رو به رشد است. توصیه می کنیم اگر هنوز امتحان نکرده اید، آن را امتحان کنید. برای گامهای بعدی، به مستندات رسمی Kotlin به همراه راهنمای نحوه اعمال الگوهای رایج Kotlin در برنامههای Android خود نگاهی بیندازید.