|
|
<!DOCTYPE html>
|
|
|
<!--
|
|
|
==============================================================================
|
|
|
"GitHub HTML5 Pandoc Template" v2.1 — by Tristano Ajmone
|
|
|
==============================================================================
|
|
|
Copyright © Tristano Ajmone, 2017, MIT License (MIT). Project's home:
|
|
|
|
|
|
- https://github.com/tajmone/pandoc-goodies
|
|
|
|
|
|
The CSS in this template reuses source code taken from the following projects:
|
|
|
|
|
|
- GitHub Markdown CSS: Copyright © Sindre Sorhus, MIT License (MIT):
|
|
|
https://github.com/sindresorhus/github-markdown-css
|
|
|
|
|
|
- Primer CSS: Copyright © 2016-2017 GitHub Inc., MIT License (MIT):
|
|
|
http://primercss.io/
|
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
The MIT License
|
|
|
|
|
|
Copyright (c) Tristano Ajmone, 2017 (github.com/tajmone/pandoc-goodies)
|
|
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
|
|
Copyright (c) 2017 GitHub Inc.
|
|
|
|
|
|
"GitHub Pandoc HTML5 Template" is Copyright (c) Tristano Ajmone, 2017, released
|
|
|
under the MIT License (MIT); it contains readaptations of substantial portions
|
|
|
of the following third party softwares:
|
|
|
|
|
|
(1) "GitHub Markdown CSS", Copyright (c) Sindre Sorhus, MIT License (MIT).
|
|
|
(2) "Primer CSS", Copyright (c) 2016 GitHub Inc., MIT License (MIT).
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
SOFTWARE.
|
|
|
==============================================================================-->
|
|
|
<html>
|
|
|
<head>
|
|
|
<meta charset="utf-8" />
|
|
|
<meta name="generator" content="pandoc" />
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
|
<meta name="author" content="Laurent Provot" />
|
|
|
<title>Introduction à Kotlin</title>
|
|
|
<style type="text/css">
|
|
|
.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;color:#24292e;font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:16px;line-height:1.5;word-wrap:break-word;box-sizing:border-box;min-width:200px;max-width:980px;margin:0 auto;padding:45px}.markdown-body a{color:#0366d6;background-color:transparent;text-decoration:none;-webkit-text-decoration-skip:objects}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body a:hover{text-decoration:underline}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body strong{font-weight:600}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h1{font-size:2em;margin:.67em 0;padding-bottom:.3em;border-bottom:1px solid #eaecef}.markdown-body h2{padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid #eaecef}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{font-size:.85em;color:#6a737d}.markdown-body img{border-style:none}.markdown-body svg:not(:root){overflow:hidden}.markdown-body hr{box-sizing:content-box;height:.25em;margin:24px 0;padding:0;overflow:hidden;background-color:#e1e4e8;border:0}.markdown-body hr::before{display:table;content:""}.markdown-body hr::after{display:table;clear:both;content:""}.markdown-body input{margin:0;overflow:visible;font:inherit;font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body [type=checkbox]{box-sizing:border-box;padding:0}.markdown-body *{box-sizing:border-box}.markdown-body blockquote{margin:0}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body li>p{margin-top:16px}.markdown-body li+li{margin-top:.25em}.markdown-body dd{margin-left:0}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:600}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body code{font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace}.markdown-body pre{font:12px SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;word-wrap:normal}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body blockquote{padding:0 1em;color:#6a737d;border-left:.25em solid #dfe2e5}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body table{display:block;width:100%;overflow:auto;border-spacing:0;border-collapse:collapse}.markdown-body table th{font-weight:600}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #dfe2e5}.markdown-body table tr{background-color:#fff;border-top:1px solid #c6cbd1}.markdown-body table tr:nth-child(2n){background-color:#f6f8fa}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body code{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(27,31,35,.05);border-radius:3px}.markdown-body code::after,.markdown-body code::before{letter-spacing:-.2em;content:"\00a0"}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f6f8fa;border-radius:3px}.markdown-body pre code{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code::after,.markdown-body pre code::before{content:normal}.markdown-body .full-commit .btn-outline:not(:disabled):hover{color:#005cc5;border-color:#005cc5}.markdown-body kbd{box-shadow:inset 0 -1px 0 #959da5;display:inline-block;padding:3px 5px;font:11px/10px SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;color:#444d56;vertical-align:middle;background-color:#fcfcfc;border:1px solid #c6cbd1;border-bottom-color:#959da5;border-radius:3px;box-shadow:inset 0 -1px 0 #959da5}.markdown-body :checked+.radio-label{position:relative;z-index:1;border-color:#0366d6}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item+.task-list-item{margin-top:3px}.markdown-body .task-list-item input{margin:0 .2em .25em -1.6em;vertical-align:middle}.markdown-body::before{display:table;content:""}.markdown-body::after{display:table;clear:both;content:""}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.Alert,.Error,.Note,.Success,.Warning{padding:11px;margin-bottom:24px;border-style:solid;border-width:1px;border-radius:4px}.Alert p,.Error p,.Note p,.Success p,.Warning p{margin-top:0}.Alert p:last-child,.Error p:last-child,.Note p:last-child,.Success p:last-child,.Warning p:last-child{margin-bottom:0}.Alert{color:#246;background-color:#e2eef9;border-color:#bac6d3}.Warning{color:#4c4a42;background-color:#fff9ea;border-color:#dfd8c2}.Error{color:#911;background-color:#fcdede;border-color:#d2b2b2}.Success{color:#22662c;background-color:#e2f9e5;border-color:#bad3be}.Note{color:#2f363d;background-color:#f6f8fa;border-color:#d5d8da}.Alert h1,.Alert h2,.Alert h3,.Alert h4,.Alert h5,.Alert h6{color:#246;margin-bottom:0}.Warning h1,.Warning h2,.Warning h3,.Warning h4,.Warning h5,.Warning h6{color:#4c4a42;margin-bottom:0}.Error h1,.Error h2,.Error h3,.Error h4,.Error h5,.Error h6{color:#911;margin-bottom:0}.Success h1,.Success h2,.Success h3,.Success h4,.Success h5,.Success h6{color:#22662c;margin-bottom:0}.Note h1,.Note h2,.Note h3,.Note h4,.Note h5,.Note h6{color:#2f363d;margin-bottom:0}.Alert h1:first-child,.Alert h2:first-child,.Alert h3:first-child,.Alert h4:first-child,.Alert h5:first-child,.Alert h6:first-child,.Error h1:first-child,.Error h2:first-child,.Error h3:first-child,.Error h4:first-child,.Error h5:first-child,.Error h6:first-child,.Note h1:first-child,.Note h2:first-child,.Note h3:first-child,.Note h4:first-child,.Note h5:first-child,.Note h6:first-child,.Success h1:first-child,.Success h2:first-child,.Success h3:first-child,.Success h4:first-child,.Success h5:first-child,.Success h6:first-child,.Warning h1:first-child,.Warning h2:first-child,.Warning h3:first-child,.Warning h4:first-child,.Warning h5:first-child,.Warning h6:first-child{margin-top:0}h1.title,p.subtitle{text-align:center}h1.title.followed-by-subtitle{margin-bottom:0}p.subtitle{font-size:1.5em;font-weight:600;line-height:1.25;margin-top:0;margin-bottom:16px;padding-bottom:.3em}div.line-block{white-space:pre-line}
|
|
|
</style>
|
|
|
<style type="text/css">code{white-space: pre;}</style>
|
|
|
<style type="text/css">
|
|
|
a.sourceLine { display: inline-block; line-height: 1.25; }
|
|
|
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
|
|
|
a.sourceLine:empty { height: 1.2em; }
|
|
|
.sourceCode { overflow: visible; }
|
|
|
code.sourceCode { white-space: pre; position: relative; }
|
|
|
div.sourceCode { margin: 1em 0; }
|
|
|
pre.sourceCode { margin: 0; }
|
|
|
@media screen {
|
|
|
div.sourceCode { overflow: auto; }
|
|
|
}
|
|
|
@media print {
|
|
|
code.sourceCode { white-space: pre-wrap; }
|
|
|
a.sourceLine { text-indent: -1em; padding-left: 1em; }
|
|
|
}
|
|
|
pre.numberSource a.sourceLine
|
|
|
{ position: relative; left: -4em; }
|
|
|
pre.numberSource a.sourceLine::before
|
|
|
{ content: attr(data-line-number);
|
|
|
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
|
|
border: none; pointer-events: all; display: inline-block;
|
|
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
|
|
-khtml-user-select: none; -moz-user-select: none;
|
|
|
-ms-user-select: none; user-select: none;
|
|
|
padding: 0 4px; width: 4em;
|
|
|
color: #aaaaaa;
|
|
|
}
|
|
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|
|
div.sourceCode
|
|
|
{ }
|
|
|
@media screen {
|
|
|
a.sourceLine::before { text-decoration: underline; }
|
|
|
}
|
|
|
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
|
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
|
|
code span.at { color: #7d9029; } /* Attribute */
|
|
|
code span.bn { color: #40a070; } /* BaseN */
|
|
|
code span.bu { } /* BuiltIn */
|
|
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
|
|
code span.ch { color: #4070a0; } /* Char */
|
|
|
code span.cn { color: #880000; } /* Constant */
|
|
|
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
|
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
|
|
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
|
|
code span.dt { color: #902000; } /* DataType */
|
|
|
code span.dv { color: #40a070; } /* DecVal */
|
|
|
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
|
|
code span.ex { } /* Extension */
|
|
|
code span.fl { color: #40a070; } /* Float */
|
|
|
code span.fu { color: #06287e; } /* Function */
|
|
|
code span.im { } /* Import */
|
|
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
|
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
|
|
code span.op { color: #666666; } /* Operator */
|
|
|
code span.ot { color: #007020; } /* Other */
|
|
|
code span.pp { color: #bc7a00; } /* Preprocessor */
|
|
|
code span.sc { color: #4070a0; } /* SpecialChar */
|
|
|
code span.ss { color: #bb6688; } /* SpecialString */
|
|
|
code span.st { color: #4070a0; } /* String */
|
|
|
code span.va { color: #19177c; } /* Variable */
|
|
|
code span.vs { color: #4070a0; } /* VerbatimString */
|
|
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
|
|
</style>
|
|
|
<!--[if lt IE 9]>
|
|
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
|
|
<![endif]-->
|
|
|
</head>
|
|
|
<body>
|
|
|
<article class="markdown-body">
|
|
|
<header>
|
|
|
<!--<h1 class="title">Introduction à Kotlin</h1>-->
|
|
|
<p class="date">Septembre 2022</p>
|
|
|
</header>
|
|
|
<h1 id="introduction-à-kotlin">Introduction à Kotlin</h1>
|
|
|
<h2 id="pourquoi-kotlin">Pourquoi Kotlin</h2>
|
|
|
<ul>
|
|
|
<li>Google I/O 2017 : langage de premier ordre pour Android</li>
|
|
|
<li><p>Intégré par défaut à partir d’Android Studio 3.0</p></li>
|
|
|
<li>Langage à typage statique</li>
|
|
|
<li>S’exécute sur une JVM (et par extension sur ART)</li>
|
|
|
<li>Beaucoup d’inférence de type, donc moins verbeux que Java</li>
|
|
|
<li>Multiparadigme (procedural, fonctionnel, orienté objets)</li>
|
|
|
<li><p>Pousse aux <em>best practices</em></p></li>
|
|
|
</ul>
|
|
|
<p>Pour l’auto-apprentissage : <a href="https://kotlinlang.org/docs/home.html" class="uri">https://kotlinlang.org/docs/home.html</a> — <a href="https://play.kotlinlang.org/" class="uri">https://play.kotlinlang.org/</a></p>
|
|
|
<h2 id="règles-de-base">Règles de base</h2>
|
|
|
<ul>
|
|
|
<li>Code contenu dans des fichiers <code>.kt</code></li>
|
|
|
<li>Pas besoin de <code>;</code> en fin de ligne</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb1"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">main</span>(<span class="va">args</span>: <span class="dt">Array</span><<span class="va">String</span>>) {</a>
|
|
|
<a class="sourceLine" id="cb1-2" data-line-number="2"> println(<span class="st">"Hello Kotlin"</span>)</a>
|
|
|
<a class="sourceLine" id="cb1-3" data-line-number="3">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Déclarations à la UML</li>
|
|
|
<li>Conventions de nommage très similaires à Java<br />
|
|
|
cf. <a href="https://kotlinlang.org/docs/coding-conventions.html" class="uri">https://kotlinlang.org/docs/coding-conventions.html</a></li>
|
|
|
</ul>
|
|
|
<h2 id="types">Types</h2>
|
|
|
<ul>
|
|
|
<li>Pas de types primitifs</li>
|
|
|
<li>Action sans résultat : singleton <code>Unit</code> (≈<code>void</code> de Java)</li>
|
|
|
<li>Rien, fonction qui ne termine pas normalement : <code>Nothing</code></li>
|
|
|
<li>Nombres : <code>Double</code>, <code>Float</code>, <code>Long</code>, <code>Int</code>, <code>Short</code>, <code>Byte</code></li>
|
|
|
<li>Pas de conversions implicite : <code>toInt()</code>, <code>toFloat()</code>, …</li>
|
|
|
<li>Littéraux : comme en Java (<code>0b101010</code>, <code>0xB8</code>, <code>12</code>, <code>3.14f</code>)</li>
|
|
|
<li>Possibilité de séparateur <code>1_000_000</code></li>
|
|
|
<li>Booléens : <code>Boolean</code> (<code>true</code> et <code>false</code>)</li>
|
|
|
<li><p>Tableaux : classe <code>Array</code> (<code>get</code>, <code>set</code>, <code>[]</code>, <code>size</code>) + fonctions</p></li>
|
|
|
<li>Texte : <code>Char</code>, <code>String</code></li>
|
|
|
<li>Les chaînes de caractères sont <em>immuables</em></li>
|
|
|
<li><code>"Hello\tTab"</code> (escaped string) ou <code>""" avec saut de lignes """</code> (raw string)</li>
|
|
|
<li><p>Utilisation possible de <em>string templates</em> :</p></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb2"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb2-1" data-line-number="1"><span class="kw">val</span> <span class="va">name</span> = <span class="st">"Laurent"</span></a>
|
|
|
<a class="sourceLine" id="cb2-2" data-line-number="2"><span class="kw">val</span> <span class="va">greetings</span> = <span class="st">"Salut $name !"</span></a>
|
|
|
<a class="sourceLine" id="cb2-3" data-line-number="3"><span class="kw">val</span> <span class="va">scream</span> = <span class="st">"EH HO… ${name.toUpperCase()} !"</span></a></code></pre></div>
|
|
|
<h2 id="références">Références</h2>
|
|
|
<ul>
|
|
|
<li><p><code>val</code> : reférence une valeur constante (immuable)</p>
|
|
|
<div class="sourceCode" id="cb3"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="kw">val</span> <span class="va">answer</span> : <span class="kw">Int</span> = <span class="dv">42</span></a>
|
|
|
<a class="sourceLine" id="cb3-2" data-line-number="2"><span class="kw">val</span> <span class="va">age</span> = <span class="dv">33</span>; <span class="co">// Type inféré</span></a>
|
|
|
<a class="sourceLine" id="cb3-3" data-line-number="3"><span class="kw">val</span> <span class="va">what</span>: <span class="kw">String</span> <span class="co">// Type nécessaire si pas d'initialisation</span></a>
|
|
|
<a class="sourceLine" id="cb3-4" data-line-number="4">what = <span class="st">"Whaaat ?"</span> <span class="co">// Initialisation différée</span></a>
|
|
|
<a class="sourceLine" id="cb3-5" data-line-number="5"></a>
|
|
|
<a class="sourceLine" id="cb3-6" data-line-number="6">age += <span class="dv">2</span> <span class="co">// Erreur, pas modifiable</span></a></code></pre></div></li>
|
|
|
<li><p><code>var</code> : reférence une variable (peu changer de valeur)</p>
|
|
|
<div class="sourceCode" id="cb4"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb4-1" data-line-number="1"><span class="kw">var</span> <span class="va">x</span> : <span class="kw">Int</span> = <span class="dv">2</span>;</a>
|
|
|
<a class="sourceLine" id="cb4-2" data-line-number="2"><span class="kw">var</span> <span class="va">y</span> = <span class="ch">'y'</span>;</a>
|
|
|
<a class="sourceLine" id="cb4-3" data-line-number="3">++x; <span class="co">// OK, muable</span></a></code></pre></div></li>
|
|
|
<li><p><code>const</code> : constante connue à la compilation</p>
|
|
|
<ul>
|
|
|
<li>soit top level, soit membre d’un <code>object</code></li>
|
|
|
<li>initialisée avec une <code>String</code> ou un valeur primitive</li>
|
|
|
<li>pas de getter personnalisé</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb5"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb5-1" data-line-number="1">const <span class="kw">val</span> <span class="va">PI_APPROX</span>: float = <span class="fl">3.14f</span>;</a></code></pre></div></li>
|
|
|
<li><p>Comparaison de références</p>
|
|
|
<ul>
|
|
|
<li><code>==</code> comparaison structurelle (<code>equals()</code>)</li>
|
|
|
<li><code>===</code> comparaison d’instances (emplacement mémoire)</li>
|
|
|
</ul></li>
|
|
|
</ul>
|
|
|
<h2 id="nullable-types">Nullable types</h2>
|
|
|
<ul>
|
|
|
<li>Nullable : <code>Double?</code>, <code>String?</code>, …</li>
|
|
|
<li>Pour éviter les <code>NullPointerException</code> (NPE)</li>
|
|
|
<li><code>?.</code> pour un accès sûr</li>
|
|
|
<li>Elvis operator : <code>?:</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb6"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb6-1" data-line-number="1"><span class="kw">val</span> <span class="va">l</span>: <span class="kw">Int</span> = <span class="cf">if</span> (b != <span class="kw">null</span>) b.length <span class="cf">else</span> <span class="dv">-1</span></a>
|
|
|
<a class="sourceLine" id="cb6-2" data-line-number="2"><span class="co">// équivalent</span></a>
|
|
|
<a class="sourceLine" id="cb6-3" data-line-number="3"><span class="kw">val</span> <span class="va">l</span> = b?.length ?: <span class="dv">-1</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Forçage : <code>!!.</code> lève une NPE si l’objet est <code>null</code> (à éviter !)</li>
|
|
|
</ul>
|
|
|
<h2 id="les-intervalles-range">Les intervalles (Range)</h2>
|
|
|
<ul>
|
|
|
<li>Opérateur <code>..</code> (issu de la fonction <code>rangeTo()</code>)</li>
|
|
|
<li>Fonctions extensions : <code>until</code>, <code>downTo</code>, <code>step</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb7"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb7-1" data-line-number="1"><span class="dv">1</span>..<span class="dv">10</span> <span class="co">// de 1 inclus jusqu'à 10 inclus</span></a>
|
|
|
<a class="sourceLine" id="cb7-2" data-line-number="2"><span class="dv">1</span> until <span class="dv">10</span> <span class="co">// de 1 inclus jusqu'à 10 exclus</span></a>
|
|
|
<a class="sourceLine" id="cb7-3" data-line-number="3"><span class="dv">4</span>..<span class="dv">1</span> <span class="co">// vide</span></a>
|
|
|
<a class="sourceLine" id="cb7-4" data-line-number="4"><span class="dv">4</span> downto <span class="dv">1</span> <span class="co">// 4, 3, 2, 1</span></a>
|
|
|
<a class="sourceLine" id="cb7-5" data-line-number="5"><span class="dv">10</span> downto <span class="dv">1</span> step <span class="dv">2</span> <span class="co">// 10, 8, 6, 4, 2</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li><code>step</code> doit être strictement positif</li>
|
|
|
</ul>
|
|
|
<h2 id="le-transtypage-cast">Le transtypage (cast)</h2>
|
|
|
<ul>
|
|
|
<li>Savoir si un objet est d’un certain type : <code>is</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb8"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="cf">if</span> (obj <span class="kw">is</span> <span class="kw">String</span>) {</a>
|
|
|
<a class="sourceLine" id="cb8-2" data-line-number="2"> print(obj.trim())</a>
|
|
|
<a class="sourceLine" id="cb8-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb8-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb8-5" data-line-number="5"><span class="cf">if</span> (obj !<span class="kw">is</span> <span class="kw">String</span>) { <span class="co">// equivalent à !(obj is String)</span></a>
|
|
|
<a class="sourceLine" id="cb8-6" data-line-number="6"> print(<span class="st">"Not a String"</span>)</a>
|
|
|
<a class="sourceLine" id="cb8-7" data-line-number="7">}</a>
|
|
|
<a class="sourceLine" id="cb8-8" data-line-number="8"><span class="cf">else</span> {</a>
|
|
|
<a class="sourceLine" id="cb8-9" data-line-number="9"> print(obj.length)</a>
|
|
|
<a class="sourceLine" id="cb8-10" data-line-number="10">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Cast explicite souvent inutile : le compilateur s’en occupe (smart cast)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb9"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb9-1" data-line-number="1"><span class="co">// x est automatiquement casté en String à droite du ||</span></a>
|
|
|
<a class="sourceLine" id="cb9-2" data-line-number="2"><span class="cf">if</span> (x !<span class="kw">is</span> <span class="kw">String</span> || x.length == <span class="dv">0</span>) <span class="kw">return</span></a>
|
|
|
<a class="sourceLine" id="cb9-3" data-line-number="3"></a>
|
|
|
<a class="sourceLine" id="cb9-4" data-line-number="4"><span class="co">// x est automatiquement casté en String à droite du && et dans le if</span></a>
|
|
|
<a class="sourceLine" id="cb9-5" data-line-number="5"><span class="cf">if</span> (x <span class="kw">is</span> <span class="kw">String</span> && x.length > <span class="dv">0</span>) {</a>
|
|
|
<a class="sourceLine" id="cb9-6" data-line-number="6"> print(x.length)</a>
|
|
|
<a class="sourceLine" id="cb9-7" data-line-number="7">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>On peut néamoins caster avec <code>as</code> (unsafe cast)</li>
|
|
|
<li>Lève une exception si pas possible</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb10"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb10-1" data-line-number="1"><span class="kw">val</span> <span class="va">x</span>: <span class="kw">String</span> = y <span class="kw">as</span> <span class="kw">String</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Utiliser <code>as?</code> pour safe cast</li>
|
|
|
<li>Le résultat est un nullable type</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb11"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb11-1" data-line-number="1"><span class="kw">val</span> <span class="va">x</span>: <span class="kw">String</span>? = y <span class="kw">as</span>? <span class="kw">String</span></a></code></pre></div>
|
|
|
<h2 id="contrôle-du-flot-dexécution">Contrôle du flot d’exécution</h2>
|
|
|
<ul>
|
|
|
<li><code>if</code>, <code>while</code>, <code>break</code>, <code>continue</code> : comme en Java</li>
|
|
|
<li>possibilité de labels : <code>unLabel@</code> … <code>break@unLabel</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb12"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb12-1" data-line-number="1">loop@ <span class="cf">for</span> (i <span class="kw">in</span> <span class="dv">1</span>..<span class="dv">100</span>) {</a>
|
|
|
<a class="sourceLine" id="cb12-2" data-line-number="2"> <span class="cf">for</span> (j <span class="kw">in</span> <span class="dv">1</span>..<span class="dv">100</span>) {</a>
|
|
|
<a class="sourceLine" id="cb12-3" data-line-number="3"> <span class="cf">if</span> (…) break<span class="at">@loop</span></a>
|
|
|
<a class="sourceLine" id="cb12-4" data-line-number="4"> }</a>
|
|
|
<a class="sourceLine" id="cb12-5" data-line-number="5">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li><code>when</code> : équivalent du <code>switch</code> (mais plus sympa)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb13"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb13-1" data-line-number="1"><span class="cf">when</span> (x) {</a>
|
|
|
<a class="sourceLine" id="cb13-2" data-line-number="2"> <span class="dv">0</span>, <span class="dv">1</span> -> print(<span class="st">"peu"</span>)</a>
|
|
|
<a class="sourceLine" id="cb13-3" data-line-number="3"> <span class="kw">in</span> <span class="dv">2</span>..<span class="dv">10</span> -> print(<span class="st">"moyen"</span>)</a>
|
|
|
<a class="sourceLine" id="cb13-4" data-line-number="4"> <span class="kw">is</span> <span class="kw">String</span> -> print(<span class="st">"${x.trim()} est une String"</span>)</a>
|
|
|
<a class="sourceLine" id="cb13-5" data-line-number="5"> <span class="cf">else</span> -> {</a>
|
|
|
<a class="sourceLine" id="cb13-6" data-line-number="6"> println(<span class="st">"rien de tout ça"</span>)</a>
|
|
|
<a class="sourceLine" id="cb13-7" data-line-number="7"> print(<span class="st">"on peu mettre un block"</span>)</a>
|
|
|
<a class="sourceLine" id="cb13-8" data-line-number="8"> }</a>
|
|
|
<a class="sourceLine" id="cb13-9" data-line-number="9">}</a></code></pre></div>
|
|
|
<div class="sourceCode" id="cb14"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb14-1" data-line-number="1">println(</a>
|
|
|
<a class="sourceLine" id="cb14-2" data-line-number="2"> <span class="cf">when</span> {</a>
|
|
|
<a class="sourceLine" id="cb14-3" data-line-number="3"> x.isOdd() -> <span class="st">"impair"</span></a>
|
|
|
<a class="sourceLine" id="cb14-4" data-line-number="4"> x.isEven() -> <span class="st">"pair"</span></a>
|
|
|
<a class="sourceLine" id="cb14-5" data-line-number="5"> <span class="cf">else</span> -> <span class="st">"bizarre"</span></a>
|
|
|
<a class="sourceLine" id="cb14-6" data-line-number="6">})</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li><code>when</code> et <code>if</code> peuvent êrte utilisées comme expressions : elles renvoient comme valeur le resultat de leur dernière instruction exécutée</li>
|
|
|
<li><code>for</code> : parcours sur tout ce qui fournit un itérateur (<code>foreach</code> de C#), i.e. :
|
|
|
<ul>
|
|
|
<li>fournit une méthode <code>iterator()</code></li>
|
|
|
<li>cet itérateur a une méthode <code>next()</code> et une méthode <code>hasNext()</code> qui retourne un <code>Boolean</code> (doivent être marquées <code>operator</code>)</li>
|
|
|
</ul></li>
|
|
|
<li>Itération classique (intervalle, String, Array, …)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb15"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb15-1" data-line-number="1"><span class="cf">for</span> (i <span class="kw">in</span> <span class="dv">0</span>..<span class="dv">9</span>) {</a>
|
|
|
<a class="sourceLine" id="cb15-2" data-line-number="2"> println(i)</a>
|
|
|
<a class="sourceLine" id="cb15-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb15-4" data-line-number="4"><span class="cf">for</span> (c <span class="kw">in</span> <span class="st">"Hello"</span>) {</a>
|
|
|
<a class="sourceLine" id="cb15-5" data-line-number="5"> println(c)</a>
|
|
|
<a class="sourceLine" id="cb15-6" data-line-number="6">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Itération avec indices</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb16"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb16-1" data-line-number="1"><span class="cf">for</span> (i <span class="kw">in</span> array.indices) {</a>
|
|
|
<a class="sourceLine" id="cb16-2" data-line-number="2"> println(array[i])</a>
|
|
|
<a class="sourceLine" id="cb16-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb16-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb16-5" data-line-number="5"><span class="cf">for</span> ((index, value) <span class="kw">in</span> array.withIndex()) {</a>
|
|
|
<a class="sourceLine" id="cb16-6" data-line-number="6"> println(<span class="st">"The element at $index is $value"</span>)</a>
|
|
|
<a class="sourceLine" id="cb16-7" data-line-number="7">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Pour les execptions : comme en Java (sauf qu’il n’existe pas de notion de <em>checked exception</em>)</li>
|
|
|
<li><code>try/catch/finally</code> est un expression</li>
|
|
|
</ul>
|
|
|
<h2 id="les-fonctions">Les fonctions</h2>
|
|
|
<ul>
|
|
|
<li>Possibilité de fonction <em>top level</em> (pas forcément membre d’un objet)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb17"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb17-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">sum</span>(<span class="va">a</span>: <span class="dt">Int</span>, <span class="va">b</span>: <span class="dt">Int</span>): <span class="dt">Int</span> {</a>
|
|
|
<a class="sourceLine" id="cb17-2" data-line-number="2"> <span class="kw">return</span> a + b</a>
|
|
|
<a class="sourceLine" id="cb17-3" data-line-number="3">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Avec inférence du type de retour pour les <em>expression body</em> (pratique pour getter/setter)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb18"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb18-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">sum</span>(<span class="va">a</span>: <span class="dt">Int</span>, <span class="va">b</span>: <span class="dt">Int</span>) = a + b</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Paramètres avec valeur par défaut (pratique pour les Ctor)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb19"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb19-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">say</span>(<span class="va">text</span>: <span class="dt">String</span> = <span class="st">"Something"</span>) = println(text)</a>
|
|
|
<a class="sourceLine" id="cb19-2" data-line-number="2">say() <span class="co">// Affiche Something</span></a>
|
|
|
<a class="sourceLine" id="cb19-3" data-line-number="3">say(<span class="st">"Hi guys"</span>) <span class="co">// Affiche Hi guys</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Paramètres nommés</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb20"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb20-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">Box</span>.<span class="fu">setMargins</span>(<span class="va">left</span>: <span class="dt">Int</span>, <span class="va">top</span>: <span class="dt">Int</span>, <span class="va">right</span>: <span class="dt">Int</span>, <span class="va">bottom</span>: <span class="dt">Int</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb20-2" data-line-number="2"></a>
|
|
|
<a class="sourceLine" id="cb20-3" data-line-number="3">myBox.setMargins(<span class="dv">10</span>,<span class="dv">10</span>,<span class="dv">20</span>,<span class="dv">20</span>) <span class="co">// haut ? bas ? gauche ? droite ?</span></a>
|
|
|
<a class="sourceLine" id="cb20-4" data-line-number="4">myBox.setMargins(left = <span class="dv">10</span>, right = <span class="dv">10</span>, top = <span class="dv">20</span>, bottom = <span class="dv">20</span>)</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Paramètres variables (<code>Type...</code> de Java)</li>
|
|
|
<li>Utilisation du <em>spread</em> operator (*) pour paramètres nommés</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb21"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb21-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">foo</span>(<span class="kw">vararg</span> <span class="va">strings</span>: <span class="dt">String</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb21-2" data-line-number="2">foo(<span class="st">"s1"</span>, <span class="st">"s2"</span>)</a>
|
|
|
<a class="sourceLine" id="cb21-3" data-line-number="3">foo(strings = *arrayOf(<span class="st">"a"</span>, <span class="st">"b"</span>, <span class="st">"c"</span>))</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>On peut déclarer une fonction dans une autre fonction</li>
|
|
|
<li>Utile pour récursivité terminale</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb22"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb22-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">dfs</span>(<span class="va">graph</span>: <span class="dt">Graph</span>) {</a>
|
|
|
<a class="sourceLine" id="cb22-2" data-line-number="2"> <span class="kw">val</span> <span class="va">visited</span> = HashSet<Vertex>()</a>
|
|
|
<a class="sourceLine" id="cb22-3" data-line-number="3"></a>
|
|
|
<a class="sourceLine" id="cb22-4" data-line-number="4"> <span class="kw">fun</span> <span class="fu">dfs</span>(<span class="va">current</span>: <span class="dt">Vertex</span>) {</a>
|
|
|
<a class="sourceLine" id="cb22-5" data-line-number="5"> <span class="cf">if</span> (!visited.add(current)) <span class="kw">return</span></a>
|
|
|
<a class="sourceLine" id="cb22-6" data-line-number="6"> <span class="cf">for</span> (v <span class="kw">in</span> current.neighbors)</a>
|
|
|
<a class="sourceLine" id="cb22-7" data-line-number="7"> dfs(v)</a>
|
|
|
<a class="sourceLine" id="cb22-8" data-line-number="8"> }</a>
|
|
|
<a class="sourceLine" id="cb22-9" data-line-number="9"></a>
|
|
|
<a class="sourceLine" id="cb22-10" data-line-number="10"> dfs(graph.vertices[<span class="dv">0</span>])</a>
|
|
|
<a class="sourceLine" id="cb22-11" data-line-number="11">}</a></code></pre></div>
|
|
|
<h2 id="classes-et-objets">Classes et objets</h2>
|
|
|
<ul>
|
|
|
<li>Squelette de classe standard en Java (entre POJO et Bean)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb23"><pre class="sourceCode java"><code class="sourceCode java"><a class="sourceLine" id="cb23-1" data-line-number="1"><span class="kw">class</span> Person {</a>
|
|
|
<a class="sourceLine" id="cb23-2" data-line-number="2"> <span class="kw">private</span> <span class="bu">String</span> name;</a>
|
|
|
<a class="sourceLine" id="cb23-3" data-line-number="3"> <span class="kw">private</span> <span class="dt">int</span> age;</a>
|
|
|
<a class="sourceLine" id="cb23-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb23-5" data-line-number="5"> <span class="kw">public</span> <span class="fu">Person</span>(<span class="bu">String</span> name, <span class="dt">int</span> age) {</a>
|
|
|
<a class="sourceLine" id="cb23-6" data-line-number="6"> <span class="kw">this</span>.<span class="fu">name</span> = name;</a>
|
|
|
<a class="sourceLine" id="cb23-7" data-line-number="7"> <span class="kw">this</span>.<span class="fu">age</span> = age;</a>
|
|
|
<a class="sourceLine" id="cb23-8" data-line-number="8"> }</a>
|
|
|
<a class="sourceLine" id="cb23-9" data-line-number="9"></a>
|
|
|
<a class="sourceLine" id="cb23-10" data-line-number="10"> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">getName</span>() { <span class="kw">return</span> name; }</a>
|
|
|
<a class="sourceLine" id="cb23-11" data-line-number="11"> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">setName</span>(<span class="bu">String</span> name) { <span class="kw">this</span>.<span class="fu">name</span> = name; }</a>
|
|
|
<a class="sourceLine" id="cb23-12" data-line-number="12"> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">getAge</span>() { <span class="kw">return</span> age; }</a>
|
|
|
<a class="sourceLine" id="cb23-13" data-line-number="13"> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">setAge</span>(<span class="dt">int</span> age) { <span class="kw">this</span>.<span class="fu">age</span> = age; }</a>
|
|
|
<a class="sourceLine" id="cb23-14" data-line-number="14"></a>
|
|
|
<a class="sourceLine" id="cb23-15" data-line-number="15"> <span class="kw">public</span> <span class="dt">int</span> <span class="fu">hashCode</span>() { … }</a>
|
|
|
<a class="sourceLine" id="cb23-16" data-line-number="16"> <span class="kw">public</span> <span class="dt">boolean</span> <span class="fu">equals</span>() { … }</a>
|
|
|
<a class="sourceLine" id="cb23-17" data-line-number="17"></a>
|
|
|
<a class="sourceLine" id="cb23-18" data-line-number="18"> <span class="at">@Override</span></a>
|
|
|
<a class="sourceLine" id="cb23-19" data-line-number="19"> <span class="kw">public</span> <span class="fu">toString</span>() {</a>
|
|
|
<a class="sourceLine" id="cb23-20" data-line-number="20"> <span class="kw">return</span> <span class="st">"Person(name="</span> + name + <span class="st">", age="</span> + age + <span class="st">")"</span>;</a>
|
|
|
<a class="sourceLine" id="cb23-21" data-line-number="21"> }</a>
|
|
|
<a class="sourceLine" id="cb23-22" data-line-number="22">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>L’équivalent en Kotlin</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb24"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb24-1" data-line-number="1"><span class="kw">data</span> <span class="kw">class</span> Person(<span class="kw">var</span> <span class="va">name</span>: <span class="dt">String</span>, <span class="kw">var</span> <span class="va">age</span>: <span class="dt">Int</span>)</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>\o/ sympa… mais contraintes :
|
|
|
<ul>
|
|
|
<li>Ne peut pas être <code>abstract</code>, <code>open</code>, <code>sealed</code>, <code>inner</code></li>
|
|
|
<li>Ctor principal doit avoir au moins un paramètre</li>
|
|
|
<li>Les paramètres doivent tous être marqués <code>val</code> ou <code>var</code></li>
|
|
|
<li><code>equals()</code>, <code>hashCode()</code>, <code>toString()</code> non générée si présentes explicitement</li>
|
|
|
</ul></li>
|
|
|
<li>Instanciation : pas besoin de <code>new</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb25"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb25-1" data-line-number="1"><span class="kw">val</span> <span class="va">moi</span> = Person(<span class="st">"Laurent Provot"</span>, <span class="dv">27</span>)</a></code></pre></div>
|
|
|
<h2 id="visibilités">Visibilités</h2>
|
|
|
<table>
|
|
|
<colgroup>
|
|
|
<col style="width: 14%" />
|
|
|
<col style="width: 41%" />
|
|
|
<col style="width: 44%" />
|
|
|
</colgroup>
|
|
|
<thead>
|
|
|
<tr class="header">
|
|
|
<th>Modifieur</th>
|
|
|
<th>Package</th>
|
|
|
<th>Classe</th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
<tbody>
|
|
|
<tr class="odd">
|
|
|
<td><code>public</code></td>
|
|
|
<td>partout</td>
|
|
|
<td>à tout ceux qui voient la classe</td>
|
|
|
</tr>
|
|
|
<tr class="even">
|
|
|
<td><code>private</code></td>
|
|
|
<td>au sein du fichier contenant la déclaration</td>
|
|
|
<td>au sein de la classe uniquement</td>
|
|
|
</tr>
|
|
|
<tr class="odd">
|
|
|
<td><code>internal</code></td>
|
|
|
<td>dans le même module</td>
|
|
|
<td>dans le même module à qui voit la classe</td>
|
|
|
</tr>
|
|
|
<tr class="even">
|
|
|
<td><code>protected</code></td>
|
|
|
<td>—</td>
|
|
|
<td>comme <code>private</code> + dans les classes dérivées</td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
|
</table>
|
|
|
<ul>
|
|
|
<li>module : ensemble de fichiers Kotlin compilés ensemble (pour Android = Gradle source set)</li>
|
|
|
</ul>
|
|
|
<h2 id="constructeur-ctor">Constructeur (Ctor)</h2>
|
|
|
<ul>
|
|
|
<li>Constructeur principal</li>
|
|
|
<li>On ne peut pas spécifier de code tout de suite</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb26"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb26-1" data-line-number="1"><span class="kw">class</span> Person <span class="kw">constructor</span>(<span class="va">firstName</span>: <span class="dt">String</span>) {…}</a>
|
|
|
<a class="sourceLine" id="cb26-2" data-line-number="2"><span class="kw">class</span> Person(<span class="va">firstName</span>: <span class="dt">String</span>) {…}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Bloc d’initialisation</li>
|
|
|
<li>On peut utiliser les paramètres du ctor principal dans les blocs d’initialisation et les initialisations d’attributs</li>
|
|
|
<li>Initialisations effectuées dans l’ordre declaré</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb27"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb27-1" data-line-number="1"><span class="kw">class</span> Person(<span class="va">name</span>: <span class="dt">String</span>) {</a>
|
|
|
<a class="sourceLine" id="cb27-2" data-line-number="2"> <span class="kw">val</span> <span class="va">nameUpper</span> = name.toUpperCase();</a>
|
|
|
<a class="sourceLine" id="cb27-3" data-line-number="3"></a>
|
|
|
<a class="sourceLine" id="cb27-4" data-line-number="4"> init {</a>
|
|
|
<a class="sourceLine" id="cb27-5" data-line-number="5"> println(<span class="st">"My name is: $name"</span>);</a>
|
|
|
<a class="sourceLine" id="cb27-6" data-line-number="6"> }</a>
|
|
|
<a class="sourceLine" id="cb27-7" data-line-number="7">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Pour initialisation de propriétés</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb28"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb28-1" data-line-number="1"><span class="kw">class</span> Person(<span class="kw">val</span> <span class="va">firstName</span>: <span class="dt">String</span>, <span class="kw">var</span> <span class="va">age</span>: <span class="dt">Int</span>) { … }</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Si annotations ou modificateur (visibilité, …)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb29"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb29-1" data-line-number="1"><span class="kw">class</span> Person <span class="kw">private</span> <span class="kw">constructor</span>(<span class="kw">val</span> <span class="va">firstName</span>: <span class="dt">String</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb29-2" data-line-number="2"><span class="kw">class</span> Person @Inject <span class="kw">constructor</span>(<span class="kw">val</span> <span class="va">firstName</span>: <span class="dt">String</span>) { … }</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Ctor secondaires</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb30"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb30-1" data-line-number="1"><span class="kw">class</span> Person(<span class="kw">val</span> <span class="va">name</span>: <span class="dt">String</span>) {</a>
|
|
|
<a class="sourceLine" id="cb30-2" data-line-number="2"> <span class="kw">constructor</span>(name: Streing, parent: Person) : <span class="kw">this</span>(name) {</a>
|
|
|
<a class="sourceLine" id="cb30-3" data-line-number="3"> parent.children.add(<span class="kw">this</span>)</a>
|
|
|
<a class="sourceLine" id="cb30-4" data-line-number="4"> }</a>
|
|
|
<a class="sourceLine" id="cb30-5" data-line-number="5">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Délégation au contructeur principal obligatoire (implicite sinon)</li>
|
|
|
<li>Tous les blocs d’initialisation sont appelés</li>
|
|
|
<li>Ctor par défaut si non précisé ou si tous les paramètres ont des valeurs par défaut</li>
|
|
|
</ul>
|
|
|
<h2 id="propriétés-getter-setter">Propriétés & getter / setter</h2>
|
|
|
<ul>
|
|
|
<li>Attribut déclaré avec <code>val</code> = propriété en lecture seule</li>
|
|
|
<li>Attribut déclaré avec <code>var</code> = propriété en lecture / écriture</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb31"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb31-1" data-line-number="1"><span class="kw">class</span> Person {</a>
|
|
|
<a class="sourceLine" id="cb31-2" data-line-number="2"> <span class="kw">var</span> <span class="va">name</span> = <span class="st">"John Doe"</span>;</a>
|
|
|
<a class="sourceLine" id="cb31-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb31-4" data-line-number="4">john = Person();</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Accès : <code>john.name</code> (utilisation du getter)</li>
|
|
|
<li>Modification : <code>john.name = "johnny"</code> (utilisation du setter)</li>
|
|
|
<li>Syntaxe complète</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb32"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb32-1" data-line-number="1"><span class="kw">var</span> <<span class="va">propertyName</span>>[: PropertyType] [= <initializer>]</a>
|
|
|
<a class="sourceLine" id="cb32-2" data-line-number="2"> [<getter>] </a>
|
|
|
<a class="sourceLine" id="cb32-3" data-line-number="3"> [<setter>]</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Propriété personnalisée : accès à l’attribut avec <code>field</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb33"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb33-1" data-line-number="1"><span class="kw">var</span> <span class="va">speed</span>: <span class="kw">Int</span></a>
|
|
|
<a class="sourceLine" id="cb33-2" data-line-number="2"> <span class="kw">get</span>() = field * <span class="dv">100</span>; </a>
|
|
|
<a class="sourceLine" id="cb33-3" data-line-number="3"> <span class="kw">set</span>(value) {</a>
|
|
|
<a class="sourceLine" id="cb33-4" data-line-number="4"> <span class="cf">if</span> (value >= <span class="dv">0</span>) field = value;</a>
|
|
|
<a class="sourceLine" id="cb33-5" data-line-number="5"> }</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Attribut (<em>backing field</em>) fourni seulement si nécessaire</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb34"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb34-1" data-line-number="1"><span class="kw">val</span> <span class="va">isEmpty</span>: <span class="kw">Boolean</span></a>
|
|
|
<a class="sourceLine" id="cb34-2" data-line-number="2"> <span class="kw">get</span>() = <span class="kw">this</span>.size == <span class="dv">0</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Changement de visibilité ou ajout d’annotation en conservant l’implémentation par défaut</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb35"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb35-1" data-line-number="1"><span class="kw">var</span> <span class="va">devOnly</span>: <span class="kw">String</span></a>
|
|
|
<a class="sourceLine" id="cb35-2" data-line-number="2"> <span class="at">@NotNull</span> <span class="kw">get</span></a>
|
|
|
<a class="sourceLine" id="cb35-3" data-line-number="3"> <span class="kw">private</span> <span class="kw">set</span></a></code></pre></div>
|
|
|
<h2 id="héritage">Héritage</h2>
|
|
|
<ul>
|
|
|
<li>Hiérarchie basée sur la classe <code>Any</code> (≠ <code>java.lang.Object</code>)</li>
|
|
|
<li>Autorisation excplicite de l’héritage avec <code>open</code> (l’opposé de <code>final</code> en Java)</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb36"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb36-1" data-line-number="1"><span class="kw">open</span> <span class="kw">class</span> Base(<span class="va">arg</span>: <span class="dt">String</span>)</a>
|
|
|
<a class="sourceLine" id="cb36-2" data-line-number="2"><span class="kw">class</span> Derived(<span class="va">num</span>: <span class="dt">Int</span>) : <span class="dt">Base</span>(<span class="va">arg</span>.<span class="va">toString</span>())</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Ctor secondaires : appel obligatoire de <code>super</code> ou délégation à un autre ctor</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb37"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb37-1" data-line-number="1"><span class="kw">class</span> Derived : <span class="dt">Base</span> {</a>
|
|
|
<a class="sourceLine" id="cb37-2" data-line-number="2"> <span class="kw">constructor</span>(arg: <span class="kw">String</span>, num: <span class="kw">Int</span>) : <span class="kw">super</span>(arg) {…}</a>
|
|
|
<a class="sourceLine" id="cb37-3" data-line-number="3"> <span class="kw">constructor</span>(arg: <span class="kw">String</span>) : <span class="kw">this</span>(arg, <span class="dv">42</span>)</a>
|
|
|
<a class="sourceLine" id="cb37-4" data-line-number="4">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Redéfinition de méthode : explicite avec <code>override</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb38"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb38-1" data-line-number="1"><span class="kw">open</span> <span class="kw">class</span> Base {</a>
|
|
|
<a class="sourceLine" id="cb38-2" data-line-number="2"> <span class="kw">open</span> <span class="kw">fun</span> <span class="fu">fo</span>() {…}</a>
|
|
|
<a class="sourceLine" id="cb38-3" data-line-number="3"> <span class="kw">fun</span> <span class="fu">fc</span>() {…}</a>
|
|
|
<a class="sourceLine" id="cb38-4" data-line-number="4">}</a>
|
|
|
<a class="sourceLine" id="cb38-5" data-line-number="5"><span class="kw">class</span> Derived() : <span class="dt">Base</span>() {</a>
|
|
|
<a class="sourceLine" id="cb38-6" data-line-number="6"> <span class="kw">override</span> <span class="kw">fun</span> <span class="fu">fo</span>() {…}</a>
|
|
|
<a class="sourceLine" id="cb38-7" data-line-number="7">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Un membre déclaré <code>override</code> est automatiquement <code>open</code>; si non désiré : le marquer <code>final</code></li>
|
|
|
<li>Redéfinition de propriété : pareil que pour les méthodes</li>
|
|
|
<li>On peut redéfinir un <code>val</code> en <code>var</code></li>
|
|
|
<li><code>override</code> peut être utilisé dans le constructeur prinicpal</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb39"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb39-1" data-line-number="1"><span class="kw">open</span> <span class="kw">class</span> Base {</a>
|
|
|
<a class="sourceLine" id="cb39-2" data-line-number="2"> <span class="kw">open</span> <span class="kw">val</span> <span class="va">x</span>: <span class="kw">Int</span> = <span class="dv">0</span> </a>
|
|
|
<a class="sourceLine" id="cb39-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb39-4" data-line-number="4"><span class="kw">class</span> Derived : <span class="dt">Base</span>() {</a>
|
|
|
<a class="sourceLine" id="cb39-5" data-line-number="5"> <span class="kw">override</span> <span class="kw">var</span> <span class="va">x</span>: <span class="kw">Int</span> = <span class="dv">42</span></a>
|
|
|
<a class="sourceLine" id="cb39-6" data-line-number="6">}</a>
|
|
|
<a class="sourceLine" id="cb39-7" data-line-number="7"><span class="kw">class</span> AnotherDerived(<span class="kw">override</span> <span class="kw">val</span> <span class="va">x</span>: <span class="dt">Int</span>) : <span class="dt">Base</span>()</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Comme en Java, le code de la classe dérivée peut appeler des méthodes/propriétés de sa classe de base grâce au mot clé <code>super</code></li>
|
|
|
<li>Classe et méthode abstraite : déclarées avec le mot clé <code>abstract</code></li>
|
|
|
<li><code>abstract</code> implique <code>open</code></li>
|
|
|
</ul>
|
|
|
<h2 id="interfaces">Interfaces</h2>
|
|
|
<ul>
|
|
|
<li>Comme en Java</li>
|
|
|
<li>Une interface peut contenir des propriétés mais elles seront soit abstraites, soit <code>val</code> et sans <em>backing field</em></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb40"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb40-1" data-line-number="1"><span class="kw">interface</span> Named {</a>
|
|
|
<a class="sourceLine" id="cb40-2" data-line-number="2"> <span class="kw">val</span> <span class="va">name</span>: <span class="kw">String</span></a>
|
|
|
<a class="sourceLine" id="cb40-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb40-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb40-5" data-line-number="5"><span class="kw">interface</span> FullNamed : <span class="dt">Named</span> {</a>
|
|
|
<a class="sourceLine" id="cb40-6" data-line-number="6"> <span class="kw">val</span> <span class="va">firstName</span>: <span class="kw">String</span></a>
|
|
|
<a class="sourceLine" id="cb40-7" data-line-number="7"> <span class="kw">val</span> <span class="va">lastName</span>: <span class="kw">String</span></a>
|
|
|
<a class="sourceLine" id="cb40-8" data-line-number="8"> </a>
|
|
|
<a class="sourceLine" id="cb40-9" data-line-number="9"> <span class="kw">override</span> <span class="kw">val</span> <span class="va">name</span>: <span class="kw">String</span> <span class="kw">get</span>() = <span class="st">"$firstName $lastName"</span></a>
|
|
|
<a class="sourceLine" id="cb40-10" data-line-number="10">}</a>
|
|
|
<a class="sourceLine" id="cb40-11" data-line-number="11"></a>
|
|
|
<a class="sourceLine" id="cb40-12" data-line-number="12"><span class="kw">data</span> <span class="kw">class</span> Person(</a>
|
|
|
<a class="sourceLine" id="cb40-13" data-line-number="13"> <span class="kw">override</span> <span class="kw">val</span> <span class="va">firstName</span>: <span class="dt">String</span>,</a>
|
|
|
<a class="sourceLine" id="cb40-14" data-line-number="14"> <span class="kw">override</span> <span class="kw">val</span> <span class="va">lastName</span>: <span class="dt">String</span></a>
|
|
|
<a class="sourceLine" id="cb40-15" data-line-number="15">) : <span class="dt">FullNamed</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Désambiguïsation grâce à <code>super<…></code> si implémentation dans l’interface</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb41"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb41-1" data-line-number="1"><span class="kw">interface</span> A {</a>
|
|
|
<a class="sourceLine" id="cb41-2" data-line-number="2"> <span class="kw">fun</span> <span class="fu">foo</span>() { print(<span class="st">"A"</span>) }</a>
|
|
|
<a class="sourceLine" id="cb41-3" data-line-number="3">}</a>
|
|
|
<a class="sourceLine" id="cb41-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb41-5" data-line-number="5"><span class="kw">interface</span> B {</a>
|
|
|
<a class="sourceLine" id="cb41-6" data-line-number="6"> <span class="kw">fun</span> <span class="fu">foo</span>() { print(<span class="st">"B"</span>) }</a>
|
|
|
<a class="sourceLine" id="cb41-7" data-line-number="7">}</a>
|
|
|
<a class="sourceLine" id="cb41-8" data-line-number="8"></a>
|
|
|
<a class="sourceLine" id="cb41-9" data-line-number="9"><span class="kw">class</span> C : <span class="dt">A</span>, <span class="dt">B</span> {</a>
|
|
|
<a class="sourceLine" id="cb41-10" data-line-number="10"> <span class="kw">override</span> <span class="kw">fun</span> <span class="fu">foo</span>() {</a>
|
|
|
<a class="sourceLine" id="cb41-11" data-line-number="11"> <span class="kw">super</span><A>.foo()</a>
|
|
|
<a class="sourceLine" id="cb41-12" data-line-number="12"> <span class="kw">super</span><B>.foo()</a>
|
|
|
<a class="sourceLine" id="cb41-13" data-line-number="13"> }</a>
|
|
|
<a class="sourceLine" id="cb41-14" data-line-number="14">}</a></code></pre></div>
|
|
|
<h2 id="classes-de-données">Classes de données</h2>
|
|
|
<div class="sourceCode" id="cb42"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb42-1" data-line-number="1"><span class="kw">data</span> <span class="kw">class</span> User(<span class="kw">val</span> <span class="va">name</span>: <span class="dt">String</span>, <span class="kw">val</span> <span class="va">age</span>: <span class="dt">Int</span>)</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>En plus des propriétés, <code>toString()</code> et <code>equals()</code> / <code>hashCode()</code>
|
|
|
<ul>
|
|
|
<li><code>copy()</code></li>
|
|
|
<li><code>component1()</code>, …, <code>componentN()</code> functions</li>
|
|
|
</ul></li>
|
|
|
<li><p>Méthode <code>copy</code> :</p>
|
|
|
<div class="sourceCode" id="cb43"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb43-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">copy</span>(<span class="va">name</span>: <span class="dt">String</span> = this.name, <span class="va">age</span>: <span class="dt">Int</span> = this.age) = User(name, age)</a>
|
|
|
<a class="sourceLine" id="cb43-2" data-line-number="2"></a>
|
|
|
<a class="sourceLine" id="cb43-3" data-line-number="3"><span class="kw">val</span> <span class="va">john</span> = User(name = <span class="st">"John"</span>, age = <span class="dv">42</span>)</a>
|
|
|
<a class="sourceLine" id="cb43-4" data-line-number="4"><span class="kw">val</span> <span class="va">youngJohn</span> = john.copy(age = <span class="dv">22</span>)</a></code></pre></div></li>
|
|
|
<li>Méthodes <code>component</code> : déstructuration de la classe</li>
|
|
|
<li>Pour chaque propriété du ctor principal, dans l’ordre de déclaration</li>
|
|
|
<li><p>Underscore possible si paramètre non utilisé</p>
|
|
|
<div class="sourceCode" id="cb44"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb44-1" data-line-number="1">println(john.component1()) <span class="co">// affiche "John"</span></a>
|
|
|
<a class="sourceLine" id="cb44-2" data-line-number="2"><span class="kw">val</span> (<span class="va">name</span>, age) = john</a>
|
|
|
<a class="sourceLine" id="cb44-3" data-line-number="3">println(<span class="st">"$name, $age years old"</span>) <span class="co">// affiche "John, 42 years old"</span></a></code></pre></div></li>
|
|
|
<li><p>Sympa pour les retours de fonctions, Map, itérations avec index</p></li>
|
|
|
</ul>
|
|
|
<h2 id="object-companion-object"><code>object</code> & Companion object</h2>
|
|
|
<ul>
|
|
|
<li>Généralisation des classes anonymes de Java</li>
|
|
|
<li>Expression objet = création d’une instance locale avec certains comportements</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb45"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb45-1" data-line-number="1">button.addMouseListener(<span class="kw">object</span> : <span class="dt">MouseAdapter</span>() {</a>
|
|
|
<a class="sourceLine" id="cb45-2" data-line-number="2"> <span class="kw">override</span> <span class="kw">fun</span> <span class="fu">mouseClicked</span>(<span class="va">e</span>: <span class="dt">MouseEvent</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb45-3" data-line-number="3"> <span class="kw">override</span> <span class="kw">fun</span> <span class="fu">mouseEntered</span>(<span class="va">e</span>: <span class="dt">MouseEvent</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb45-4" data-line-number="4">})</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Création d’objet sans supertype non trivial</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb46"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb46-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">foo</span>() {</a>
|
|
|
<a class="sourceLine" id="cb46-2" data-line-number="2"> <span class="kw">val</span> <span class="va">local</span> = <span class="kw">object</span> {</a>
|
|
|
<a class="sourceLine" id="cb46-3" data-line-number="3"> <span class="kw">var</span> <span class="va">x</span>: <span class="kw">Int</span> = <span class="dv">0</span></a>
|
|
|
<a class="sourceLine" id="cb46-4" data-line-number="4"> <span class="kw">var</span> <span class="va">y</span>: <span class="kw">Int</span> = <span class="dv">0</span></a>
|
|
|
<a class="sourceLine" id="cb46-5" data-line-number="5"> }</a>
|
|
|
<a class="sourceLine" id="cb46-6" data-line-number="6"> print(local.x + local.y)</a>
|
|
|
<a class="sourceLine" id="cb46-7" data-line-number="7"> print(local::<span class="kw">class</span>.simpleName) // affiche null</a>
|
|
|
<a class="sourceLine" id="cb46-8" data-line-number="8">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li><code>object</code> comme valeur de retour</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb47"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb47-1" data-line-number="1"><span class="kw">class</span> C {</a>
|
|
|
<a class="sourceLine" id="cb47-2" data-line-number="2"> <span class="co">// Private function : the return type is the anonymous object type</span></a>
|
|
|
<a class="sourceLine" id="cb47-3" data-line-number="3"> <span class="kw">private</span> <span class="kw">fun</span> <span class="fu">foo</span>() = <span class="kw">object</span> { <span class="kw">val</span> <span class="va">x</span>: <span class="kw">String</span> = <span class="st">"x"</span>}</a>
|
|
|
<a class="sourceLine" id="cb47-4" data-line-number="4"></a>
|
|
|
<a class="sourceLine" id="cb47-5" data-line-number="5"> <span class="co">// Public function : so the return type is Any</span></a>
|
|
|
<a class="sourceLine" id="cb47-6" data-line-number="6"> <span class="kw">fun</span> <span class="fu">publicFoo</span>() = <span class="kw">object</span> { <span class="kw">val</span> <span class="va">x</span>: <span class="kw">String</span> = <span class="st">"x"</span> }</a>
|
|
|
<a class="sourceLine" id="cb47-7" data-line-number="7"></a>
|
|
|
<a class="sourceLine" id="cb47-8" data-line-number="8"> <span class="kw">fun</span> <span class="fu">bar</span>() {</a>
|
|
|
<a class="sourceLine" id="cb47-9" data-line-number="9"> <span class="kw">val</span> <span class="va">x1</span> = foo().x <span class="co">// OK</span></a>
|
|
|
<a class="sourceLine" id="cb47-10" data-line-number="10"> <span class="kw">val</span> <span class="va">x2</span> = publicFoo().x <span class="co">// ERROR: Unresolved reference 'x'</span></a>
|
|
|
<a class="sourceLine" id="cb47-11" data-line-number="11"> }</a>
|
|
|
<a class="sourceLine" id="cb47-12" data-line-number="12">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Déclaration d’objet = singletons</li>
|
|
|
<li>Initialisation thread-safe</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb48"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb48-1" data-line-number="1"><span class="kw">object</span> DatabaseManager { </a>
|
|
|
<a class="sourceLine" id="cb48-2" data-line-number="2"> <span class="kw">fun</span> <span class="fu">connect</span>(<span class="va">conn</span>: <span class="dt">Connector</span>) { … }</a>
|
|
|
<a class="sourceLine" id="cb48-3" data-line-number="3"> <span class="kw">fun</span> <span class="fu">fetchData</span>() : <span class="dt">Data</span> { … }</a>
|
|
|
<a class="sourceLine" id="cb48-4" data-line-number="4">}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Ne peut pas être du côté droit d’une affectation</li>
|
|
|
<li>Ne peut pas être déclaré local</li>
|
|
|
<li>Déclaration dans une classe possible avec le mot clé <code>companion</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb49"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb49-1" data-line-number="1"><span class="kw">class</span> MyClass {</a>
|
|
|
<a class="sourceLine" id="cb49-2" data-line-number="2"> <span class="kw">companion</span> <span class="kw">object</span> Factory {</a>
|
|
|
<a class="sourceLine" id="cb49-3" data-line-number="3"> <span class="kw">fun</span> <span class="fu">create</span>(): <span class="dt">MyClass</span> = MyClass()</a>
|
|
|
<a class="sourceLine" id="cb49-4" data-line-number="4"> }</a>
|
|
|
<a class="sourceLine" id="cb49-5" data-line-number="5">}</a>
|
|
|
<a class="sourceLine" id="cb49-6" data-line-number="6"></a>
|
|
|
<a class="sourceLine" id="cb49-7" data-line-number="7"><span class="kw">val</span> <span class="va">instance</span> = MyClass.create()</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Utilisation à la <code>static</code> de Java</li>
|
|
|
<li>Mais attention <code>Factory</code> implique une instance d’objet</li>
|
|
|
<li>Utilisation de <code>@JvmStatic</code> si on veut que cela génère des membres <code>static</code> dans le bytecode Java</li>
|
|
|
<li>Les expressions objet sont exécutées <em>immédiatement</em>, les déclarations objet sont initialisées de manière <em>paresseuse</em> et les <code>companion object</code> au moment du chargement de leur classe d’attachement</li>
|
|
|
</ul>
|
|
|
<h2 id="retour-sur-les-fonctions">Retour sur les fonctions</h2>
|
|
|
<ul>
|
|
|
<li>Les fonctions sont des variables comme les autres</li>
|
|
|
<li>Elles ont un type :
|
|
|
<ul>
|
|
|
<li><code>(A, B) -> C</code> : une fonction qui prend 2 paramètres le premier de type <code>A</code>, le second de type <code>B</code> et retoune un <code>C</code></li>
|
|
|
<li><code>() -> A</code> : pas de paramètre en entrée</li>
|
|
|
<li><code>(A) -> Unit</code> : pas de valeur de retour</li>
|
|
|
<li><code>A.(B) -> C</code> : fonction qui peut être appelée sur un objet de type <code>A</code>, prend un paramètre de type <code>B</code> et retourne une valeur de type <code>C</code></li>
|
|
|
</ul></li>
|
|
|
<li>Création concise grâce aux lambda</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb50"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb50-1" data-line-number="1"><span class="kw">val</span> <span class="va">square</span> = { num: <span class="kw">Int</span> -> num * num }; <span class="co">// (Int) -> Int</span></a>
|
|
|
<a class="sourceLine" id="cb50-2" data-line-number="2"><span class="kw">val</span> <span class="va">more</span> : (<span class="kw">String</span>, <span class="kw">Int</span>) -> <span class="kw">String</span> = { str, num -> str + num }</a>
|
|
|
<a class="sourceLine" id="cb50-3" data-line-number="3"><span class="kw">val</span> <span class="va">noReturn</span> : <span class="kw">Int</span> -> <span class="kw">Unit</span> = { num -> println(num) }</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Pour les lambdas qui ne prennent qu’un paramètre : <code>it</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb51"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb51-1" data-line-number="1"><span class="kw">val</span> <span class="va">noReturn</span> : <span class="kw">Int</span> -> <span class="kw">Unit</span> = { println(it) }</a>
|
|
|
<a class="sourceLine" id="cb51-2" data-line-number="2"><span class="kw">val</span> <span class="va">concatInt</span> : <span class="kw">String</span>.(<span class="kw">Int</span>) -> <span class="kw">String</span> = { <span class="kw">this</span> + it }</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Utilisation</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb52"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb52-1" data-line-number="1"><span class="kw">fun</span> <<span class="dt">T</span>, <span class="dt">R</span>> <span class="fu">Collection</span><<span class="dt">T</span>>.<span class="fu">fold</span>(</a>
|
|
|
<a class="sourceLine" id="cb52-2" data-line-number="2"> <span class="va">initial</span>: <span class="dt">R</span>, </a>
|
|
|
<a class="sourceLine" id="cb52-3" data-line-number="3"> <span class="va">combine</span>: (<span class="dt">acc</span>: <span class="dt">R</span>, <span class="dt">nextElement</span>: <span class="dt">T</span>) -> <span class="dt">R</span></a>
|
|
|
<a class="sourceLine" id="cb52-4" data-line-number="4">): <span class="dt">R</span> {</a>
|
|
|
<a class="sourceLine" id="cb52-5" data-line-number="5"> <span class="kw">var</span> <span class="va">accumulator</span>: R = initial</a>
|
|
|
<a class="sourceLine" id="cb52-6" data-line-number="6"> <span class="cf">for</span> (element: T <span class="kw">in</span> <span class="kw">this</span>) {</a>
|
|
|
<a class="sourceLine" id="cb52-7" data-line-number="7"> accumulator = combine(accumulator, element)</a>
|
|
|
<a class="sourceLine" id="cb52-8" data-line-number="8"> }</a>
|
|
|
<a class="sourceLine" id="cb52-9" data-line-number="9"> <span class="kw">return</span> accumulator</a>
|
|
|
<a class="sourceLine" id="cb52-10" data-line-number="10">}</a>
|
|
|
<a class="sourceLine" id="cb52-11" data-line-number="11"></a>
|
|
|
<a class="sourceLine" id="cb52-12" data-line-number="12"><span class="kw">val</span> <span class="va">items</span> = listOf(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>)</a>
|
|
|
<a class="sourceLine" id="cb52-13" data-line-number="13">items.(<span class="dv">0</span>, {acc, i -> acc + i}) <span class="co">// 15</span></a>
|
|
|
<a class="sourceLine" id="cb52-14" data-line-number="14">items.(<span class="st">"Elts :"</span>, {res, i -> res + <span class="st">" "</span> + i}) <span class="co">// "Elts : 1 2 3 4 5"</span></a>
|
|
|
<a class="sourceLine" id="cb52-15" data-line-number="15">items.(<span class="dv">1</span>, <span class="kw">Int</span>::times) <span class="co">// 120</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Une fonction de type <code>A.(B) -> C</code> peut être utilisée en lieu et place de <code>(A, B) -> C</code> et vice versa</li>
|
|
|
<li>Lorsque le dernier paramètre d’une fonction est une fonction, si on passe un lambda on peut la sortir des parenthèses</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb53"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb53-1" data-line-number="1">items.fold(<span class="dv">0</span>) {sum, i -> sum + i}</a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Fonctions d’extension</li>
|
|
|
<li>Possible d’ajouter des fonctions à une classe après coup</li>
|
|
|
<li>Toutes les instances peuvent en profiter</li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb54"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb54-1" data-line-number="1"><span class="kw">fun</span> <span class="fu">String</span>.<span class="fu">reverse</span>() = StringBuilder(<span class="kw">this</span>).reverse.toString()</a>
|
|
|
<a class="sourceLine" id="cb54-2" data-line-number="2"><span class="st">"That's cool !"</span>.reverse() <span class="co">// "! looc s'tahT"</span></a></code></pre></div>
|
|
|
<ul>
|
|
|
<li>Fonction infixes : <code>infix</code>
|
|
|
<ul>
|
|
|
<li>Fonction membre ou fonction d’extension</li>
|
|
|
<li>Un seul paramètre</li>
|
|
|
<li>Pas de <code>vararg</code> ou de paramètre par défaut</li>
|
|
|
</ul></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb55"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb55-1" data-line-number="1"><span class="kw">infix</span> <span class="kw">fun</span> <span class="fu">String</span>.<span class="kw">open</span>(<span class="va">rights</span>: <span class="dt">Acces</span>): <span class="dt">File</span> { … }</a>
|
|
|
<a class="sourceLine" id="cb55-2" data-line-number="2"></a>
|
|
|
<a class="sourceLine" id="cb55-3" data-line-number="3"><span class="st">"/home/provot/lecture"</span> <span class="kw">open</span> Access.WRITE</a>
|
|
|
<a class="sourceLine" id="cb55-4" data-line-number="4"><span class="co">// équivalent à</span></a>
|
|
|
<a class="sourceLine" id="cb55-5" data-line-number="5"><span class="st">"/home/provot/lecture"</span>.open(Access.WRITE)</a></code></pre></div>
|
|
|
<h2 id="surcharge-dopérateur">Surcharge d’opérateur</h2>
|
|
|
<ul>
|
|
|
<li>Il est possible de surcharger les opérateurs</li>
|
|
|
<li>On redéfinit des méthodes spécifiques de la classe</li>
|
|
|
<li>Elles sont marquées <code>operator</code></li>
|
|
|
<li>+, -, *, /, %, ..
|
|
|
<ul>
|
|
|
<li><code>a + b</code> équivalent à <code>a.plus(b)</code></li>
|
|
|
<li><code>a..b</code> équivalent à <code>a.rangeTo(b)</code></li>
|
|
|
</ul></li>
|
|
|
<li><code>in</code>, <code>!in</code>
|
|
|
<ul>
|
|
|
<li><code>a.contains(b)</code></li>
|
|
|
</ul></li>
|
|
|
<li>Accès indexé <code>[]</code>
|
|
|
<ul>
|
|
|
<li><code>a[i]</code> équivalent à <code>a.get(i)</code></li>
|
|
|
<li><code>a[i] = b</code> équivalent à <code>a.set(i, b)</code></li>
|
|
|
</ul></li>
|
|
|
<li>Appel de méthode
|
|
|
<ul>
|
|
|
<li><code>a(i, j)</code> équivalent à <code>a.invoke(i, j)</code></li>
|
|
|
</ul></li>
|
|
|
<li>a == b
|
|
|
<ul>
|
|
|
<li><code>a?.equals(b) ?: (b === null)</code></li>
|
|
|
</ul></li>
|
|
|
<li>a > b, a < b, a >= b, a <= b
|
|
|
<ul>
|
|
|
<li>obtenus à partir de <code>a.compareTo(b)</code></li>
|
|
|
</ul></li>
|
|
|
</ul>
|
|
|
<h2 id="documentation">Documentation</h2>
|
|
|
<ul>
|
|
|
<li>KDoc + génération avec Dokka</li>
|
|
|
<li>Comme la javadoc</li>
|
|
|
<li>Tags : <code>@param</code>, <code>@return</code>, <code>@constructor</code>, <code>@receiver</code>, <code>@property</code>, <code>@throws</code>, <code>@exception</code>, <code>@sample</code>, <code>@see</code>, <code>@author</code>, <code>@since</code> et <code>@suppress</code></li>
|
|
|
</ul>
|
|
|
<div class="sourceCode" id="cb56"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><a class="sourceLine" id="cb56-1" data-line-number="1"><span class="co">/**</span></a>
|
|
|
<a class="sourceLine" id="cb56-2" data-line-number="2"><span class="co"> * A group of *members*.</span></a>
|
|
|
<a class="sourceLine" id="cb56-3" data-line-number="3"><span class="co"> *</span></a>
|
|
|
<a class="sourceLine" id="cb56-4" data-line-number="4"><span class="co"> * This class has no useful logic; it's just a documentation example.</span></a>
|
|
|
<a class="sourceLine" id="cb56-5" data-line-number="5"><span class="co"> *</span></a>
|
|
|
<a class="sourceLine" id="cb56-6" data-line-number="6"><span class="co"> * @param T the type of a member in this group.</span></a>
|
|
|
<a class="sourceLine" id="cb56-7" data-line-number="7"><span class="co"> * @property name the name of this group.</span></a>
|
|
|
<a class="sourceLine" id="cb56-8" data-line-number="8"><span class="co"> * @constructor Creates an empty group.</span></a>
|
|
|
<a class="sourceLine" id="cb56-9" data-line-number="9"><span class="co"> */</span></a>
|
|
|
<a class="sourceLine" id="cb56-10" data-line-number="10"><span class="kw">class</span> Group<<span class="dt">T</span>>(<span class="kw">val</span> <span class="va">name</span>: <span class="dt">String</span>) {</a>
|
|
|
<a class="sourceLine" id="cb56-11" data-line-number="11"> <span class="co">/**</span></a>
|
|
|
<a class="sourceLine" id="cb56-12" data-line-number="12"><span class="co"> * Adds a [member] to this group.</span></a>
|
|
|
<a class="sourceLine" id="cb56-13" data-line-number="13"><span class="co"> * @return the new size of the group.</span></a>
|
|
|
<a class="sourceLine" id="cb56-14" data-line-number="14"><span class="co"> */</span></a>
|
|
|
<a class="sourceLine" id="cb56-15" data-line-number="15"> <span class="kw">fun</span> <span class="fu">add</span>(<span class="va">member</span>: <span class="dt">T</span>): <span class="dt">Int</span> { ... }</a>
|
|
|
<a class="sourceLine" id="cb56-16" data-line-number="16">}</a></code></pre></div>
|
|
|
</article>
|
|
|
</body>
|
|
|
</html>
|