summaryrefslogtreecommitdiffhomepage
path: root/fr-fr/kotlin.html-fr.markdown
blob: 10f67fc41a0213d33177054d7a3911dba7927f1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
---
language: kotlin
filename: LearnKotlin-fr.kt
lang: fr-fr
contributors:
    - ["S Webber", "https://github.com/s-webber"]
translators:
    - ["Eric Ampire", "https://github.com/eric-ampire"]
---

Kotlin est un langage de programmation à typage statique pour la JVM, Android et le
navigateur. Il est 100% interopérable avec Java.
[Pour en savoir plus, cliquez ici](https://kotlinlang.org/)

```kotlin
// Les commentaires d'une seule ligne commencent par //
/*
Les commentaires de plusieurs lignes ressemblent à ceci.
*/

// Le mot-clé "package" fonctionne de la même manière qu'en Java.
   package com.learnxinyminutes.kotlin

/*
Le point d'entrée d'un programme Kotlin est une fonction appelée "main".
La fonction reçoit un tableau contenant tous les arguments de la ligne de commande.
Depuis Kotlin 1.3, la fonction "main" peut également être définie sans
tout paramètre.
*/
fun main(args: Array<String>) {
    /*
    La déclaration des valeurs se fait en utilisant soit "var" soit "val".
     Les déclarations "val" ne peuvent pas être réaffectées, alors que les déclarations "vars" le peuvent.
    */
    val fooVal = 10 // nous ne pouvons pas plus tard réaffecter fooVal à autre chose
    var fooVar = 10
    fooVar = 20 // fooVar peut être réaffecté

    /*
    Dans la plupart des cas, Kotlin peut déterminer quel est le type de variable,
    afin de ne pas avoir à le préciser explicitement à chaque fois.
    Nous pouvons déclarer explicitement le type d'une variable de cette manière :
    */
    val foo: Int = 7

    /*
    Les chaînes de caractères peuvent être représentées de la même manière qu'en Java.
    L'échappement se fait avec une barre oblique inversée.
    */
    val fooString = "Ma chaine est là !"
    val barString = "Imprimer sur une nouvelle ligne ? \nPas de problème !"
    val bazString = "Vous voulez ajouter une tabulation ? \tPas de problème !"
    println(fooString)
    println(barString)
    println(bazString)

    /*
    Une chaîne brute est délimitée par une triple citation (""").
    Les chaînes de caractères brutes peuvent contenir des nouvelles lignes et tout autre caractère.
    */
    val fooRawString = """
fun helloWorld(val name : String) {
   println("Bonjour, le monde !")
}
"""
    println(fooRawString)

    /*
    Les chaînes de caractères peuvent contenir des expressions modèles.
    Une expression modèle commence par le signe du dollar ($).
    */
    val fooTemplateString = "$fooString as ${fooString.length} caractères"
    println(fooTemplateString) // => Ma chaine est là ! comporte 18 caractères

    /*
    Pour qu'une variable soit considérée comme nulle, elle doit être explicitement spécifiée comme nulable.
    Une variable peut être spécifiée comme nulle en ajoutant un ? à son type.
    On peut accéder à une variable nulable en utilisant l'opérateur ?
    Nous pouvons utiliser l'opérateur ?: pour spécifier une valeur alternative à utiliser
    si une variable est nulle.
    */
    var fooNullable: String? = "abc"
    println(fooNullable?.length) // => 3
    println(fooNullable?.length ?: -1) // => 3
    fooNullable = null
    println(fooNullable?.length) // => null
    println(fooNullable?.length ?: -1) // => -1

    /*
    Les fonctions peuvent être déclarées en utilisant le mot-clé "fun".
    Les arguments des fonctions sont spécifiés entre parenthèses après le nom de la fonction.
    Les arguments de fonction peuvent éventuellement avoir une valeur par défaut.
    Le type de retour de la fonction, si nécessaire, est spécifié après les arguments.
    */
    fun hello(name: String = "world"): String {
        return "Bonjour, $name!"
    }
    println(hello("foo")) // => Bonjour, foo!
    println(hello(name = "bar")) // => Bonjour, bar!
    println(hello()) // => Bonjour, le monde!

    /*
    Un paramètre de fonction peut être marqué avec le mot-clé "vararg
    pour permettre de passer un nombre variable d'arguments à la fonction.
    */
    fun varargExample(vararg names: Int) {
        println("L'argument comporte ${names.size} éléments.")
    }
    varargExample() // => L'argument a 0 éléments
    varargExample(1) // => L'argument a 1 éléments
    varargExample(1, 2, 3) // => L'argument comporte 3 éléments

    /*
    Lorsqu'une fonction est constituée d'une seule expression, les parenthèses bouclées peuvent
    être omis. Le corps est spécifié après le symbole =.
    */
    fun odd(x: Int): Boolean = x % 2 == 1
    println(odd(6)) // => false
    println(odd(7)) // => true

    // Si le type de retour peut être déduit, alors nous n'avons pas besoin de le préciser.
    fun even(x: Int) = x % 2 == 0
    println(even(6)) // => true
    println(even(7)) // => false

    // Les fonctions peuvent prendre des fonctions d'arguments et des fonctions de retour.
    fun not(f: (Int) -> Boolean): (Int) -> Boolean {
        return {n -> !f.invoke(n)}
    }
    // Les fonctions nommées peuvent être spécifiées comme arguments en utilisant l'opérateur :: .
    val notOdd = not(::odd)
    val notEven = not(::even)
    // Les expressions lambda peuvent être spécifiées en tant qu'arguments.
    val notZero = not {n -> n == 0}
    /*
    Si un lambda n'a qu'un seul paramètre
    alors sa déclaration peut être omise (ainsi que le ->).
    Le nom du paramètre unique sera "it".
    */
    val notPositive = not {it > 0}
    for (i in 0..4) {
        println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}")
    }

    // Le mot-clé "class" est utilisé pour déclarer les classes.
    class ExampleClass(val x: Int) {
        fun memberFunction(y: Int): Int {
            return x + y
        }

        infix fun infixMemberFunction(y: Int): Int {
            return x * y
        }
    }
    /*
    Pour créer une nouvelle instance, nous appelons le constructeur.
    Notez que Kotlin n'a pas de mot-clé "new" .
    */
    val fooExampleClass = ExampleClass(7)
    // Les fonctions des membres peuvent être appelées en utilisant la notation par points.
    println(fooExampleClass.memberFunction(4)) // => 11
    /*
    Si une fonction a été marquée avec le mot-clé "infix", elle peut être
    appelé en utilisant la notation infixe.
    */
    println(fooExampleClass infixMemberFunction 4) // => 28

    /*
    Les classes de données sont une façon concise de créer des classes qui ne contiennent que des données.
    Les méthodes "hashCode"/"equals" et "toString" sont générées automatiquement.
    */
    data class DataClassExample (val x: Int, val y: Int, val z: Int)
    val fooData = DataClassExample(1, 2, 4)
    println(fooData) // => DataClassExample(x=1, y=2, z=4)

    // Les classes de données ont une methode "copy".
    val fooCopy = fooData.copy(y = 100)
    println(fooCopy) // => DataClassExample(x=1, y=100, z=4)

    // Les objets peuvent être déstructurés en plusieurs variables.
    val (a, b, c) = fooCopy
    println("$a $b $c") // => 1 100 4

    // La déstructuration en boucle "for"
    for ((a, b, c) in listOf(fooData)) {
        println("$a $b $c") // => 1 100 4
    }

    val mapData = mapOf("a" to 1, "b" to 2)
    // Map.Entry est également déstructurable
    for ((key, value) in mapData) {
        println("$key -> $value")
    }

    // La fonction "with" est similaire à la déclaration "with" de JavaScript.
    data class MutableDataClassExample (var x: Int, var y: Int, var z: Int)
    val fooMutableData = MutableDataClassExample(7, 4, 9)
    with (fooMutableData) {
        x -= 2
        y += 2
        z--
    }
    println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8)

    /*
    Nous pouvons créer une liste en utilisant la fonction "listOf".
    La liste sera immuable - les éléments ne peuvent être ajoutés ou supprimés.
    */
    val fooList = listOf("a", "b", "c")
    println(fooList.size) // => 3
    println(fooList.first()) // => a
    println(fooList.last()) // => c
    // Les éléments d'une liste sont accessibles par leur index.
    println(fooList[1]) // => b

    // Une liste mutable peut être créée en utilisant la fonction "mutableListOf".
    val fooMutableList = mutableListOf("a", "b", "c")
    fooMutableList.add("d")
    println(fooMutableList.last()) // => d
    println(fooMutableList.size) // => 4

    // Nous pouvons créer un ensemble en utilisant la fonction "setOf".
    val fooSet = setOf("a", "b", "c")
    println(fooSet.contains("a")) // => true
    println(fooSet.contains("z")) // => false

    // Nous pouvons créer un map en utilisant la fonction "mapOf".
    val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9)
    // Map values can be accessed by their key.
    println(fooMap["a"]) // => 8

    /*
    Les séquences représentent des collections évaluées paresseusement.
    Nous pouvons créer une séquence en utilisant la fonction "generateSequence".
    */
    val fooSequence = generateSequence(1, { it + 1 })
    val x = fooSequence.take(10).toList()
    println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    // Un exemple d'utilisation d'une séquence pour générer des nombres de Fibonacci :
    fun fibonacciSequence(): Sequence<Long> {
        var a = 0L
        var b = 1L

        fun next(): Long {
            val result = a + b
            a = b
            b = result
            return a
        }

        return generateSequence(::next)
    }
    val y = fibonacciSequence().take(10).toList()
    println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

    // Kotlin offre des fonctions d'ordre supérieur pour le travail avec les collections.
    val z = (1..9).map {it * 3}
                  .filter {it < 20}
                  .groupBy {it % 2 == 0}
                  .mapKeys {if (it.key) "even" else "odd"}
    println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]}

    // Une boucle "for" peut être utilisée avec tout ce qui fournit un itérateur.
    for (c in "hello") {
        println(c)
    }

    // Les boucles "while" fonctionnent de la même manière que les autres langues.
    var ctr = 0
    while (ctr < 5) {
        println(ctr)
        ctr++
    }
    do {
        println(ctr)
        ctr++
    } while (ctr < 10)

    /*
    "if" peut être utilisé comme une expression qui renvoie une valeur.
    Pour cette raison, l'opérateur ternaire ?: n'est pas nécessaire dans Kotlin.
    */
    val num = 5
    val message = if (num % 2 == 0) "even" else "odd"
    println("$num is $message") // => 5 is odd

    // Le terme "when" peut être utilisé comme alternative aux chaînes "if-else if".
    val i = 10
    when {
        i < 7 -> println("first block")
        fooString.startsWith("hello") -> println("second block")
        else -> println("else block")
    }

    // "when" peut être utilisé avec un argument.
    when (i) {
        0, 21 -> println("0 or 21")
        in 1..20 -> println("in the range 1 to 20")
        else -> println("none of the above")
    }

    // "when" peut être utilisé comme une fonction qui renvoie une valeur.
    var result = when (i) {
        0, 21 -> "0 or 21"
        in 1..20 -> "in the range 1 to 20"
        else -> "none of the above"
    }
    println(result)

    /*
    Nous pouvons vérifier si un objet est d'un type particulier en utilisant l'opérateur "is".
    Si un objet passe avec succès une vérification de type, il peut être utilisé comme ce type sans
    en le diffusant explicitement.
    */
    fun smartCastExample(x: Any) : Boolean {
        if (x is Boolean) {
            // x est automatiquement converti en booléen
            return x
        } else if (x is Int) {
            // x est automatiquement converti en Int
            return x > 0
        } else if (x is String) {
            // x est automatiquement converti en String
            return x.isNotEmpty()
        } else {
            return false
        }
    }
    println(smartCastExample("Bonjour, le monde !")) // => true
    println(smartCastExample("")) // => false
    println(smartCastExample(5)) // => true
    println(smartCastExample(0)) // => false
    println(smartCastExample(true)) // => true

    // Le Smartcast fonctionne également avec le bloc when
    fun smartCastWhenExample(x: Any) = when (x) {
        is Boolean -> x
        is Int -> x > 0
        is String -> x.isNotEmpty()
        else -> false
    }

    /*
    Les extensions sont un moyen d'ajouter de nouvelles fonctionnalités à une classe.
    C'est similaire aux méthodes d'extension C#.
    */
    fun String.remove(c: Char): String {
        return this.filter {it != c}
    }
    println("Hello, world!".remove('l')) // => Heo, word!
}

// Les classes Enum sont similaires aux types Java enum.
enum class EnumExample {
    A, B, C // Les constantes Enum sont séparées par des virgules.
}
fun printEnum() = println(EnumExample.A) // => A

// Puisque chaque enum est une instance de la classe enum, ils peuvent être initialisés comme :
enum class EnumExample(val value: Int) {
    A(value = 1),
    B(value = 2),
    C(value = 3)
}
fun printProperty() = println(EnumExample.A.value) // => 1

// Chaque énum a des propriétés pour obtenir son nom et son ordinal (position) dans la déclaration de classe de l'énum :
fun printName() = println(EnumExample.A.name) // => A
fun printPosition() = println(EnumExample.A.ordinal) // => 0

/*
Le mot-clé "objet" peut être utilisé pour créer des objets singleton.
On ne peut pas l'instancier mais on peut se référer à son instance unique par son nom.
Cela est similaire aux objets singleton de Scala.
*/
object ObjectExample {
    fun hello(): String {
        return "Bonjour"
    }

    override fun toString(): String {
        return "Bonjour, c'est moi, ${ObjectExample::class.simpleName}"
    }
}


fun useSingletonObject() {
    println(ObjectExample.hello()) // => hello
    // Dans Kotlin, "Any" est la racine de la hiérarchie des classes, tout comme "Object" l'est dans Java
    val someRef: Any = ObjectExample
    println(someRef) // => Bonjour, c'est moi, ObjectExample
}


/* L'opérateur d'assertion non nulle ( !!) convertit toute valeur en un type non nul et
   lance une exception si la valeur est nulle.
*/
var b: String? = "abc"
val l = b!!.length

data class Counter(var value: Int) {
    // surcharge Counter += Int
    operator fun plusAssign(increment: Int) {
        this.value += increment
    }

    // surcharge Counter++ et ++Counter
    operator fun inc() = Counter(value + 1)

    // surcharge Counter + Counter
    operator fun plus(other: Counter) = Counter(this.value + other.value)

    // surcharge Counter * Counter
    operator fun times(other: Counter) = Counter(this.value * other.value)

    // surcharge Counter * Int
    operator fun times(value: Int) = Counter(this.value * value)

    // surcharge Counter dans Counter
    operator fun contains(other: Counter) = other.value == this.value

    // surcharge Counter[Int] = Int
    operator fun set(index: Int, value: Int) {
        this.value = index + value
    }

    // surcharge Counter instance invocation
    operator fun invoke() = println("The value of the counter is $value")

}
/* Vous pouvez également surcharger les opérateurs par des méthodes d'extension */
// surcharge -Counter
operator fun Counter.unaryMinus() = Counter(-this.value)

fun operatorOverloadingDemo() {
    var counter1 = Counter(0)
    var counter2 = Counter(5)
    counter1 += 7
    println(counter1) // => Counter(value=7)
    println(counter1 + counter2) // => Counter(value=12)
    println(counter1 * counter2) // => Counter(value=35)
    println(counter2 * 2) // => Counter(value=10)
    println(counter1 in Counter(5)) // => false
    println(counter1 in Counter(7)) // => true
    counter1[26] = 10
    println(counter1) // => Counter(value=36)
    counter1() // => La valeur est 36
    println(-counter2) // => Counter(value=-5)
}
```

### Lectures complémentaires

* [Kotlin tutorials](https://kotlinlang.org/docs/tutorials/)
* [Try Kotlin in your browser](https://play.kotlinlang.org/)
* [A list of Kotlin resources](http://kotlin.link/)