kotlin.md

Личный сайт Go-разработчика из Казани

Kotlin - статически типизированный язык для JVM, Android и браузера. Язык полностью совместим c Java. Более детальная информация здесь.

1// Однострочные комментарии начинаются с // 2/* 3А вот так выглядят многострочные комментарии. 4*/ 5 6// Ключевое слово "package" действует и используется // абсолютно также, как и в Java. 7package com.learnxinyminutes.kotlin 8 9/* 10Точкой входа в программу на языке Kotlin является функция "main". 11Приведенная ниже функция передает массив, содержащий любые аргументы из командной строки. 12*/ 13fun main(args: Array<String>) { 14 /* 15 Объявление значений производится с помощью или "var", или "val". 16 Значения объявленные с помощью "val" не могут быть изменены или перезаписаны, в то время как объявленные с помощью "var" - могут. 17 */ 18 val fooVal = 10 // мы не можем потом изменить значение fooVal на какое-либо иное 19 var fooVar = 10 20 fooVar = 20 // значение fooVar затем может быть изменено. 21 22 /* 23 В большинстве случаев Kotlin самостоятельно может определить тип переменной, поэтому нам не нужно явно указывать его каждый раз. 24 Мы можем явно объявить тип переменной следующим образом: 25 */ 26 val foo: Int = 7 27 28 /* 29 Строки могут быть представлены тем же образом, что и в Java. 30 Для экранирования используется обратный слэш. 31 */ 32 val fooString = "My String Is Here!" 33 val barString = "Printing on a new line?\nNo Problem!" 34 val bazString = "Do you want to add a tab?\tNo Problem!" 35 println(fooString) 36 println(barString) 37 println(bazString) 38 39 /* 40 Необработанная строка разделяется тройной кавычкой ("""). 41 Необработанные строки могут содержать символы новой строки и любые другие символы. 42 */ 43 val fooRawString = """ 44fun helloWorld(val name : String) { 45 println("Hello, world!") 46} 47""" 48 println(fooRawString) 49 50 /* 51 Строки могут содержать в себе шаблонные выражения. 52 Шаблонные выражения начинаются со знака доллара ($). 53 */ 54 val fooTemplateString = "$fooString has ${fooString.length} characters" 55 println(fooTemplateString) 56 57 /* 58 Переменная, которая содержит null должна быть явно обозначена как nullable. 59 Переменная может быть обозначена как nullable с помощью добавления знака вопроса(?) к ее типу. 60 Мы можем получить доступ к nullable переменной используя оператор ?. . 61 Для того, чтобы указать иное значение, если переменная является null, мы используем оператор ?: . 62 */ 63 var fooNullable: String? = "abc" 64 println(fooNullable?.length) // => 3 65 println(fooNullable?.length ?: -1) // => 3 66 fooNullable = null 67 println(fooNullable?.length) // => null 68 println(fooNullable?.length ?: -1) // => -1 69 70 /* 71 Функции могут быть объявлены с помощью ключевого слова "fun". 72 Аргументы функции указываются в скобках после имени функции. 73 Аргументы функции также могу иметь и значение по умолчанию. 74 Если требуется, то тип возвращаемого функцией значения, может быть указан после аргументов. 75 */ 76 fun hello(name: String = "world"): String { 77 return "Hello, $name!" 78 } 79 println(hello("foo")) // => Hello, foo! 80 println(hello(name = "bar")) // => Hello, bar! 81 println(hello()) // => Hello, world! 82 83 /* 84 Параметр функции может быть отмечен с помощью ключевого слова "vararg", для того чтобы позволить аргументам попасть в функцию. 85 */ 86 fun varargExample(vararg names: Int) { 87 println("Argument has ${names.size} elements") 88 } 89 varargExample() // => Argument has 0 elements 90 varargExample(1) // => Argument has 1 elements 91 varargExample(1, 2, 3) // => Argument has 3 elements 92 93 /* 94 Если функция состоит из одиночного выражения, фигурные скобки могут быть опущены. Тело функции указывается после знака = . 95 */ 96 fun odd(x: Int): Boolean = x % 2 == 1 97 println(odd(6)) // => false 98 println(odd(7)) // => true 99 100 // Если возвращаемый тип может быть выведен, то нам не нужно его дополнительно указывать. 101 fun even(x: Int) = x % 2 == 0 102 println(even(6)) // => true 103 println(even(7)) // => false 104 105 // Функции могут брать другие функции в качестве аргументов, а также могут возвращать функции. 106 fun not(f: (Int) -> Boolean): (Int) -> Boolean { 107 return {n -> !f.invoke(n)} 108 } 109 // Именованные функции могут быть определены в качестве аргументов с помощью оператора :: . 110 val notOdd = not(::odd) 111 val notEven = not(::even) 112 // Lambda-выражения могут быть определены в качестве аргументов. 113 val notZero = not {n -> n == 0} 114 /* 115 Если lambda-выражение имеет только один параметр, то ее определение может быть опущено (вместе с ->). 116 Имя этого единственного параметра будет "it". 117 */ 118 val notPositive = not {it > 0} 119 for (i in 0..4) { 120 println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}") 121 } 122 123 // Ключевое слово "class" используется для 124 // объявления классов. 125 class ExampleClass(val x: Int) { 126 fun memberFunction(y: Int): Int { 127 return x + y 128 } 129 130 infix fun infixMemberFunction(y: Int): Int { 131 return x * y 132 } 133 } 134 /* 135 Чтобы создать новый экземпляр класса, нужно вызвать конструктор. 136 Обратите внимание, что в Kotlin нет ключевого слова "new". 137 */ 138 val fooExampleClass = ExampleClass(7) 139 // Функции-члены могут быть вызваны с использованием точечной нотации. 140 println(fooExampleClass.memberFunction(4)) // => 11 141 /* 142 В случае, если функция была помечена ключевым словом "infix", она может быть вызвана с помощью инфиксной нотации. 143 */ 144 println(fooExampleClass infixMemberFunction 4) // => 28 145 146 /* 147 Data-классы - это компактный способ создать классы, которые лишь хранят данные. 148 Методы "hashCode"/"equals" и "toString" генерируютсяч автоматически. 149 */ 150 data class DataClassExample (val x: Int, val y: Int, val z: Int) 151 val fooData = DataClassExample(1, 2, 4) 152 println(fooData) // => DataClassExample(x=1, y=2, z=4) 153 154 // Data-классы обладают функцией "copy". 155 val fooCopy = fooData.copy(y = 100) 156 println(fooCopy) // => DataClassExample(x=1, y=100, z=4) 157 158 // Объекты могут быть деструктурированы на множество переменных. 159 val (a, b, c) = fooCopy 160 println("$a $b $c") // => 1 100 4 161 162 // Деструктурирование в цикле "for" 163 for ((a, b, c) in listOf(fooData)) { 164 println("$a $b $c") // => 1 100 4 165 } 166 167 val mapData = mapOf("a" to 1, "b" to 2) 168 // Map.Entry также может быть дествуктурирован 169 for ((key, value) in mapData) { 170 println("$key -> $value") 171 } 172 173 // Функция "with" аналогична оператору "with" в JavaScript. 174 data class MutableDataClassExample (var x: Int, var y: Int, var z: Int) 175 val fooMutableData = MutableDataClassExample(7, 4, 9) 176 with (fooMutableData) { 177 x -= 2 178 y += 2 179 z-- 180 } 181 println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8) 182 183 /* 184 Можно создать список с помощью функции "ListOf". 185 Этот список будет неизменяемым, т.е. элементы не могут быть удалены или добавлены в него. 186 */ 187 val fooList = listOf("a", "b", "c") 188 println(fooList.size) // => 3 189 println(fooList.first()) // => a 190 println(fooList.last()) // => c 191 // Элементы списка доступны по их индексу в нем. 192 println(fooList[1]) // => b 193 194 // Изменяемый список может быть создан спомощью функции "mutableListOf". 195 val fooMutableList = mutableListOf("a", "b", "c") 196 fooMutableList.add("d") 197 println(fooMutableList.last()) // => d 198 println(fooMutableList.size) // => 4 199 200 // Мы можем создать набор, используя функцию "setOf". 201 val fooSet = setOf("a", "b", "c") 202 println(fooSet.contains("a")) // => true 203 println(fooSet.contains("z")) // => false 204 205 // Мы можем создать отображение (map), используя функцию "mapOf". 206 val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9) 207 // Получить доступ к значениям отображения (map) можно с помощью их ключа. 208 println(fooMap["a"]) // => 8 209 210 /* 211 Последовательности представляют собой коллекции с ленивой оценкой. 212 Мы можем создать последовательность, используя функцию "generateSequence". 213 */ 214 val fooSequence = generateSequence(1, { it + 1 }) 215 val x = fooSequence.take(10).toList() 216 println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 217 218 // Пример использования последовательности для генерации чисел Фибоначчи: 219 fun fibonacciSequence(): Sequence<Long> { 220 var a = 0L 221 var b = 1L 222 223 fun next(): Long { 224 val result = a + b 225 a = b 226 b = result 227 return a 228 } 229 230 return generateSequence(::next) 231 } 232 val y = fibonacciSequence().take(10).toList() 233 println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 234 235 // Kotlin предоставляет функции высшего порядка для работы с коллекциями. 236 val z = (1..9).map {it * 3} 237 .filter {it < 20} 238 .groupBy {it % 2 == 0} 239 .mapKeys {if (it.key) "even" else "odd"} 240 println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]} 241 242 // Цикл "for" может использоваться со всем, что предоставляет итератор. 243 for (c in "hello") { 244 println(c) 245 } 246 247 // Циклы "while" работают также, как и в других языках. 248 var ctr = 0 249 while (ctr < 5) { 250 println(ctr) 251 ctr++ 252 } 253 do { 254 println(ctr) 255 ctr++ 256 } while (ctr < 10) 257 258 /* 259 "if" может быть использован в качестве выражения, которое возвращает значение. 260 По этой причине в Kotlin тернарный оператор ?: не нужен. 261 */ 262 val num = 5 263 val message = if (num % 2 == 0) "even" else "odd" 264 println("$num is $message") // => 5 is odd 265 266 // "when" может быть использован как альтернатива цепочке "if-else if". 267 val i = 10 268 when { 269 i < 7 -> println("first block") 270 fooString.startsWith("hello") -> println("second block") 271 else -> println("else block") 272 } 273 274 // "when" может быть использован с аргументами. 275 when (i) { 276 0, 21 -> println("0 or 21") 277 in 1..20 -> println("in the range 1 to 20") 278 else -> println("none of the above") 279 } 280 281 // "when" также может быть использовано как функция, возвращающая значение. 282 var result = when (i) { 283 0, 21 -> "0 or 21" 284 in 1..20 -> "in the range 1 to 20" 285 else -> "none of the above" 286 } 287 println(result) 288 289 /* 290 Мы можем проверить, что объект принадлежит к определенному типу, используя оператор "is". 291 Если объект проходит проверку типа, то он может использоваться как этот тип без явной его передачи. 292 */ 293 fun smartCastExample(x: Any) : Boolean { 294 if (x is Boolean) { 295 // x is automatically cast to Boolean 296 return x 297 } else if (x is Int) { 298 // x is automatically cast to Int 299 return x > 0 300 } else if (x is String) { 301 // x is automatically cast to String 302 return x.isNotEmpty() 303 } else { 304 return false 305 } 306 } 307 println(smartCastExample("Hello, world!")) // => true 308 println(smartCastExample("")) // => false 309 println(smartCastExample(5)) // => true 310 println(smartCastExample(0)) // => false 311 println(smartCastExample(true)) // => true 312 313 // Smartcast также работает с блоком "when" 314 fun smartCastWhenExample(x: Any) = when (x) { 315 is Boolean -> x 316 is Int -> x > 0 317 is String -> x.isNotEmpty() 318 else -> false 319 } 320 321 /* 322 Расширения - это способ добавить новую функциональность к классу. 323 Это то же самое, что методы расширений в C#. 324 */ 325 fun String.remove(c: Char): String { 326 return this.filter {it != c} 327 } 328 println("Hello, world!".remove('l')) // => Heo, word! 329 330 println(EnumExample.A) // => A 331 println(ObjectExample.hello()) // => hello 332} 333 334// Enum-классы схожи с типами enum в Java. 335enum class EnumExample { 336 A, B, C 337} 338 339/* 340Ключевое слово "object" может использоваться для создания одноэлементных объектов. 341Мы не можем его инстанцировать, но можем вызывать его уникальный экземпляр по имени. 342Это похоже на одиночные объекты Scala. 343*/ 344object ObjectExample { 345 fun hello(): String { 346 return "hello" 347 } 348} 349 350fun useObject() { 351 ObjectExample.hello() 352 val someRef: Any = ObjectExample // we use objects name just as is 353}

Дальнейшее чтение: