<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Forum du club des développeurs et IT Pro - Blogs - tails</title>
		<link>https://www.developpez.net/forums/blogs/26529-tails/</link>
		<description>Developpez.com, le Club des Développeurs et IT Pro</description>
		<language>fr</language>
		<lastBuildDate>Tue, 08 Sep 2026 02:03:12 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>15</ttl>
		<image>
			<url>https://forum.developpez.be/images/misc/rss.jpg</url>
			<title>Forum du club des développeurs et IT Pro - Blogs - tails</title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/</link>
		</image>
		<item>
			<title><![CDATA[Vue JS 3 - Utilisation de propriétés calculées dans le css d'un composant]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b10171/vue-js-3-utilisation-proprietes-calculees-css-d-composant/</link>
			<pubDate>Wed, 01 Sep 2021 10:15:27 GMT</pubDate>
			<description>Bonjour :) 
 
Un besoin que...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Bonjour :)<br />
<br />
Un besoin que je rencontre de temps en temps lorsque je code mes composants VueJS, c'est celui de générer des styles css dynamiquement. L'une des possibilités réside dans l'utilisation de variables css. Mais comment s'y prendre ?<br />
<br />
Tout d'abord, dans ce billet j'utilise VueJS 3 ainsi que la nouvelle API Composition de VueJS. C'est-à-dire qu'au lieu d'utiliser les champs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">data</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">mounted</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">computed</span>..., j'utilise le champ <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">setup</span> ainsi que les nouvelles fonctions mises en place (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">onMounted</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ref</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">computed</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">watch</span>, ...).<br />
<br />
Afin d'illustrer le concept, je pars du principe que l'on souhaite créer un simple composant carré (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MyBox</span>) de couleur rouge, dont la taille est configurable via un attribut personnalisé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">sizePx</span>.<br />
<br />
Admettons pour l'instant que le composant dispose d'une taille fixe de 60px :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td valign="top"><pre style="margin: 0">
&lt;template&gt;
  &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: 'MyBox',
  props: {
    
  }
}
&lt;/script&gt;

&lt;style scoped&gt;
#root {
  width: 60px;
  height: 60px;
  background-color: red;
}
&lt;/style&gt;</pre></td></tr></table></pre>
</div>Rien de bien compliqué en soi.<br />
<br />
Ajoutons la propriété <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">sizePx</span> (lignes 8-12), qui n'aura pas encore d'effet sur la taille de notre composant :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td valign="top"><pre style="margin: 0">
&lt;template&gt;
  &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: 'MyBox',
  props: {
    sizePx: {
      type: Number,
      required: true,
    }
  }
}
&lt;/script&gt;

&lt;style scoped&gt;
#root {
  width: 60px;
  height: 60px;
  background-color: red;
}
&lt;/style&gt;</pre></td></tr></table></pre>
</div>On pourra, moyennant importation et déclaration du composant, l'utiliser de la manière suivante : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;MyBox :sizePx=&quot;100&quot; /&gt;</span>A l'heure où ce billet a été rédigé, il existait <a href="https://github.com/vuejs/rfcs/pull/231" target="_blank">une proposition de syntaxe</a> afin de pouvoir injecter des variables de notre script du composant dans le css du même composant :<br />
<ol class="decimal"><li style="">la variable en question doit être une référence</li><li style="">dans le css en question, la variable est référencée à l'aide de la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">v-bind</span></li></ol><br />
<br />
Il est fort probable que votre éditeur en ligne favori (par exemple, j'ai testé avec StackBlitz), ne supporte pas cette syntaxe : mieux vaut créer un projet avec Vue CLI (c'est-à-dire avec le générateur de projet Vue JS depuis le terminal).<br />
<br />
Voici ce que cela peut donner avec notre composant :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td valign="top"><pre style="margin: 0">
&lt;template&gt;
  &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import  {computed} from 'vue';
export default {
  name: 'MyBox',
  props: {
    sizePx: {
      type: Number,
      required: true,
    }
  },
  setup(props) {
    const size = computed(() =&gt; props.sizePx + 'px');

    return {size};
  },
}
&lt;/script&gt;

&lt;style scoped&gt;
#root {
  background-color: red;
  width: v-bind(size);
  height: v-bind(size);
}
&lt;/style&gt;</pre></td></tr></table></pre>
</div>Cette fois-ci, notre carré prend la dimension que l'on lui a indiqué.<br />
<br />
Pour cela : <br />
<ol class="decimal"><li style="">j'ai crée une variable <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">size</span>, liée à la propriété <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">sizePx</span> (ligne 16)</li><li style="">je l'ai référencée dans le css à l'aide de la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">v-bind</span> (lignes  26-27)</li></ol><br />
<br />
Ici, j'ai donné à la variable <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">size</span> la valeur de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">sizePx</span> avec l'unité Mais je peux aussi ne donner que la valeur et ajouter l'unité lors de l'appel à la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">v-bind</span> dans le css :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td valign="top"><pre style="margin: 0">
&lt;template&gt;
  &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import  {computed} from 'vue';
export default {
  name: 'MyBox',
  props: {
    sizePx: {
      type: Number,
      required: true,
    }
  },
  setup(props) {
    const size = computed(() =&gt; props.sizePx);

    return {size};
  },
}
&lt;/script&gt;

&lt;style scoped&gt;
#root {
  background-color: red;
  width: calc(v-bind(size) * 1px);
  height: calc(v-bind(size) * 1px);
}
&lt;/style&gt;</pre></td></tr></table></pre>
</div>Vous pouvez remarquer:<br />
<ol class="decimal"><li style="">l'appel à la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">calc</span></li><li style="">la multiplication de la valeur par l'unité <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">1px</span></li></ol><br />
<br />
Rien nous empêche de changer d'unité : je peux aussi écrire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">width: calc(v-bind(size) * 0.2vw);</span>,<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">width: calc(v-bind(size) * 3px);</span> ...<br />
<br />
Enfin, j'ai eu besoin dans un de mes projets d'une utilisation plus complexe :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br /></div></td><td valign="top"><pre style="margin: 0">
&lt;script&gt;
import { ref, onMounted, onBeforeUnmount } from &quot;vue&quot;;

export default {
   setup() {

      const controlsWidth = ref(0);
      const cellsSize = ref(0);

      function adjustLayoutDirection() {
          ...
          controlsWidth.value = isPortrait ? cellsSize.value * 8 + &quot;px&quot; : &quot;calc(100% - &quot; + cellsSize.value * 8 + &quot;px)&quot;;
       }

      onMounted(() =&gt; adjustLayoutDirection);
      window.addEventListener(&quot;orientationchange&quot;, adjustLayoutDirection);
      onBeforeUnmount(function () {
         window.removeEventListener(&quot;orientationchange&quot;, adjustLayoutDirection);
       });

      return {
          controlsWidth, cellsSize
       };
   }
}
&lt;/script&gt;

&lt;style scoped&gt;
#controls {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
  width: v-bind(&quot;controlsWidth&quot;);
}
&lt;/style&gt;</pre></td></tr></table></pre>
</div>Ainsi le calcul de la valeur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">controlsWidth</span> (ligne 12) est très dynamique : notamment avec l'intégration de la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">calc</span> dans la chaîne résultante en orientation paysage.<br />
<br />
Voilà, j'espère avoir bien présenté le concept. N'hésitez pas à aller voir <a href="https://github.com/vuejs/rfcs/pull/231" target="_blank">la page de la proposition de syntaxe</a>, et à expérimenter cette fonctionnalité. :D</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b10171/vue-js-3-utilisation-proprietes-calculees-css-d-composant/</guid>
		</item>
		<item>
			<title><![CDATA[Nouvelle version stable d'Android Studio et Jetpack Compose passe en version 1.0 : bref cas pratique]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b10160/nouvelle-version-stable-d-android-studio-jetpack-compose-passe-version-1-0-bref-cas-pratique/</link>
			<pubDate>Thu, 29 Jul 2021 09:25:50 GMT</pubDate>
			<description><![CDATA[Google vient d'annoncer sur...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Google vient d'annoncer <a href="https://android-developers.googleblog.com/2021/07/android-studio-arctic-fox-202031-stable.html" target="_blank">sur son blog officiel</a> la sortie de la nouvelle version stable d'Android Studio : Artic Fox 2020.3.1<br />
<br />
Parmis les nouveautés, une a particulièrement retenu mon attention : le support de la boîte à outils <a href="https://developer.android.com/jetpack/compose?hl=fr" target="_blank">Jetpack Compose</a> qui vient d'ailleurs de passer en version stable 1.0.0.<br />
<br />
Jetpack Compose a pour ambition de simplifier le développement d'applications Android. <br />
<br />
Et la première différence notable avec le développement classique d'Android réside dans le fait que l'on ne décrit plus les interfaces par le biais de fichiers XML. On décrit toute l'interface dans le code Kotlin de notre application (car oui, Jetpack Compose se code en Kotlin, et non en Java). Chaque élément d'interface est codé dans une fonction -sans valeur de retour- et annotée par @Composable. Et elle peut faire appel à d'autre éléments @Composable, dont les éléments standards mis à notre disposition. <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:132px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td valign="top"><pre style="margin: 0">
@Composable
fun MonComposant() {
    Row {
        Text(text = &quot;Hello&quot;, modifier = Modifier.background(color = Color.Blue))
        Text(text = &quot;World&quot;, modifier = Modifier.background(color = Color.Yellow))
    }
}</pre></td></tr></table></pre>
</div>(J'ai volontairement omis la liste des importations.)<br />
<br />
Où Row et Text sont des @Composable fournis par la boîte à outils Jetpack Compose. Row permet d'agencer plusieurs composants sur une ligne, Text permet d'afficher du texte. Modifier est un objet permettant ici de personnaliser les composants textes, notamment la couleur de fond ici. Modifier et Color sont aussi fournis par la boîte à outil Jetpack Compose.<br />
<br />
Rien ne nous interdit d'ajouter des paramètres afin de pouvoir décrire un composant personnalisable.<br />
<br />
Enfin, une autre nouveauté, et non des moindres, c'est qu'il est désormais possible de prévisualiser le composant dans Android Studio, avant même qu'il soit déployé dans l'émulateur/le périphérique de test. Pour cela il suffit de créer un nouveau @Composable qui utilisera notre composant, et en ajoutant l'annotation @Preview :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
@Preview
@Composable
fun MonComposantPreview() {
    MonComposant()
}</pre></td></tr></table></pre>
</div>Voici un aperçu, dont j'ai pu directement copier l'image depuis la Preview de mon composant :<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=602400&amp;d=1627552023" border="0" alt="Nom : helloworld.png
Affichages : 291
Taille : 3,8 Ko"  style="float: CONFIG" /><br />
<br />
Il y aurait évidemment beaucoup à dire pour introduire le développement d'applications avec Jetpack Compose : notamment la gestion d'états immutables/mutables,  les composants standards, les layouts, la navigation, l'utilisation de ressources texte, l'utilisation de ressources images et images vectorielles ...<br />
<br />
Je ne peux qu'inviter ceux qui désirent en savoir plus, à visiter la page de blog de Google, ainsi que la page officielle de Jetpack Compose, dont j'ai mis les liens en début de billet.</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b10160/nouvelle-version-stable-d-android-studio-jetpack-compose-passe-version-1-0-bref-cas-pratique/</guid>
		</item>
		<item>
			<title><![CDATA[[Dart] Déclarer un paramètre de type callback, avec les types.]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b10146/dart-declarer-parametre-type-callback-types/</link>
			<pubDate>Mon, 05 Jul 2021 08:08:18 GMT</pubDate>
			<description>Ce billet se base sur la...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Ce billet se base sur la version 2.13.3 du langage Dart.<br />
<br />
Le langage Dart étant un langage de typage statique, il serait bien dommage de ne pas en profiter pour l'ensemble des signatures de fonction que l'on utilise.<br />
<br />
Cependant, lorsque l'on a besoin de déclarer un callback (en variable d'instance de classe par exemple), la tâche n'est pas forcément simple. Si bien que souvent l'on écrit simplement :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
Function onReady;</pre></td></tr></table></pre>
</div>Evidemment, avec cette fonction, rien ne nous interdit de passer un paramètre, de retourner un type différent de celui attendu ...<br />
<br />
Admettons par exemple que la fonction onReady, si l'on s'en réfère à la déclaration classique, soit la suivante (En ne prêtant guère attention aux nombreuses mauvaises pratiques de celles-ci, telle que l'utilisation d'entier au lieu d'une énumération. C'est juste pour illustrer rapidement le concept dont je veux vous parler.) :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
bool onReady(int eventType) {
  if (eventType == 3) return false;
  return true;
}</pre></td></tr></table></pre>
</div>Si l'on se contente de la déclaration précédente, rien ne nous interdit d'ommettre le paramètre attendu eventType, ou de passer un 2e paramètre.<br />
<br />
En fait on peut déclarer la signature de la fonction onReady de la manière suivante :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
bool Function(int eventType) statusHandler;</pre></td></tr></table></pre>
</div>Voici un example complet d'utilisation :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:192px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td valign="top"><pre style="margin: 0">
bool Function(int eventType) statusHandlerbool onReady(int eventType) {
  if (eventType == 3) return false;
  return true;
}

void printStatus(bool Function(int eventType) statusHandler, int eventType) {
  print(statusHandler(eventType));
}

void main () {
  printStatus(onReady, 3);
}</pre></td></tr></table></pre>
</div>Et cela fonctionne aussi avec la fonctionnalité null-safety (la fonctionnalité de Dart qui vérifie si un type de variable peut ou non accepter la valeur null):<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
final void Function(int index)? handleHistoryItemRequested;</pre></td></tr></table></pre>
</div>Ainsi j'ai pu utiliser cette fonction en paramètre de constructeur dans un Widget Flutter d'un projet personnel.<br />
On constate donc que cette fonction peut prendre une valeur concrête, aussi bien que prendre null (grâce au point interrogation suivant la parenthèse de fermeture). Et cela fonctionne aussi pour les paramètres de la fonction, ainsi que le type de retour.<br />
<br />
Voilà, j'espère que vous aurez pris plaisir à lire ce billet :D</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b10146/dart-declarer-parametre-type-callback-types/</guid>
		</item>
		<item>
			<title><![CDATA[[Rust][Windows][Gtk][Relm] Déploiement d'application Gtk+Relm sous Windows : une approche possible]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b9429/rust-windows-gtk-relm-deploiement-d-application-gtkprelm-sous-windows-approche-possible/</link>
			<pubDate>Sat, 23 May 2020 11:02:05 GMT</pubDate>
			<description>Il peut paraître difficile de...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Il peut paraître difficile de créer une application Rust avec Gtk qui soit entièrement autonome sous Windows. En me basant sur <a href="https://www.gtk.org/docs/installations/windows/" target="_blank">la méthode d'installation de GTK sur le site officiel</a>, et sur <a href="https://github.com/gtk-rs/gtk/issues/422" target="_blank">ce ticket Github</a>, je vais ici essayer de répondre simplement à la problématique.<br />
<br />
<font size="7">Prérequis</font><br />
<br />
Pas de prérequis particulier au niveau du langage, le but ici étant juste d'essayer d'empaqueter un programme minimal et fonctionnel.<br />
Toutefois, si vous le souhaitez, vous pouvez regarder l'<a href="https://www.developpez.net/forums/blogs/26529-tails/b8921/rust-gtk-rs-relm-tutoriel-simple-application-saluant-l-utilisateur-prenom-qu-renseigne/" target="_blank">introduction minimaliste que j'ai rédigée sur Rust+Gtk+Relm</a>.<br />
<br />
<font size="7">Programmes à installer</font><br />
<br />
<ol class="decimal"><li style=""><a href="https://www.msys2.org/" target="_blank">Msys2</a>: utilitaire permettant notamment la compilation de programmes un peu comme sous Linux. La toolchain Gnu de Rust, qui sera utilisée, est basée sur Mingw. N'oubliez pas de vérifier l'architecture cible du binaire (i686, x86_64). Vérifiez également que le chemin C:\msys64\mingw64\bin (à adapter selon votre architecture et votre dossier d'installation de msys) figure dans les premiers résultats de votre environement PATH,</li><li style="">Rustup : l'ensemble des outils de compilation pour Rust. Attention d'installer la version GNU, et non la version MSVC. Il faut donc choisir de personnaliser l'installation et demander la version x86_64-pc-windows-gnu (architecture 64 bit) ou i686-pc-windows-gnu (architecture 32 bit). Sinon il est encore possible d'ajouter la toolchain correspondante et de la déclarer comme version par défaut : je vous laisse essayer de vous renseigner pour ce cas précis,</li><li style=""><a href="https://git-scm.com/download/win" target="_blank">Git </a>: pour pouvoir cloner le projet testé dans ce billet. Un terminal Bash est aussi fourni avec ce projet: nous l'utiliserons différentes tâches.</li></ol><br />
<br />
<font size="7">Installation des paquets de msys2 et Gtk</font><br />
<br />
Une fois Msys installé, il faut dans un 1er temps installer les paquets systèmes:<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">pacman -Syu</pre>
</div>Une fois cela finit, il faut fermer le terminal, le relancer et exécuter de nouveau la commande. <b>Recommencer le processus jusqu'à ce qu'il n'y ait plus de mise à jour à installer</b>.<br />
<br />
Puis installer Gtk: <div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">pacman -S mingw-w64-x86_64-gtk3</pre>
</div>Eventuellement, Glade: <div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">pacman -S mingw-w64-x86_64-glade</pre>
</div> pour les projets qui pourraient en avoir besoin.<br />
<br />
Et enfin, les outils tels que gcc, necessaires pour la compilation:<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">pacman -S mingw-w64-x86_64-toolchain base-devel</pre>
</div><br />
Il faut fixer la variable système globallement, <b>et non pas pour votre propre compte</b>, GTK_LIB_DIR au dossier (à adapter) C:\msys64\mingw64\lib.<br />
<br />
<font size="7">Compilation du projet</font><br />
<br />
Veuillez cloner le projet suivant (une calculatrice vraiment minimale) avec le terminal git bash, dans le dossier de votre choix<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
cd &lt;dossier_de_choix&gt;
git clone https://github.com/loloof64/SimpleCalculator.git
cd SimpleCalculator</pre></td></tr></table></pre>
</div>Veuillez compiler le projet en mode release, toujours dans le terminal git bash (ne serait-ce que parce que la commande cargo est directement reconnue) :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
cargo build --release</pre></td></tr></table></pre>
</div>Si tout se passe bien, le programme simple-calc.exe se trouve dans le sous-dossier target/release.<br />
<br />
Veuillez noter que, pour éviter que le programme ouvre un terminal lors du lancement, l'attribut #![windows_subsystem = &quot;windows&quot;] a été ajouté au début du fichier source main.rs.<br />
<br />
Nous pouvons donc lister l'ensemble des dll nécessaires pour le programme (j'ai filtré le résultat pour n'inclure que celles de mingw64):<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td valign="top"><pre style="margin: 0">
 ldd target/release/simple-calc.exe | grep mingw64
        libcairo-2.dll =&gt; /c/msys64/mingw64/bin/libcairo-2.dll (0x68dc0000)
        libgdk_pixbuf-2.0-0.dll =&gt; /c/msys64/mingw64/bin/libgdk_pixbuf-2.0-0.dll (0x6f740000)
        libgio-2.0-0.dll =&gt; /c/msys64/mingw64/bin/libgio-2.0-0.dll (0x613c0000)
        libgdk-3-0.dll =&gt; /c/msys64/mingw64/bin/libgdk-3-0.dll (0x6c1c0000)
        libgobject-2.0-0.dll =&gt; /c/msys64/mingw64/bin/libgobject-2.0-0.dll (0x67f00000)
        libglib-2.0-0.dll =&gt; /c/msys64/mingw64/bin/libglib-2.0-0.dll (0x649c0000)
        libgtk-3-0.dll =&gt; /c/msys64/mingw64/bin/libgtk-3-0.dll (0x67700000)
        libpango-1.0-0.dll =&gt; /c/msys64/mingw64/bin/libpango-1.0-0.dll (0x6d240000)
        libgmodule-2.0-0.dll =&gt; /c/msys64/mingw64/bin/libgmodule-2.0-0.dll (0x66c40000)
        libintl-8.dll =&gt; /mingw64/bin/libintl-8.dll (0x61cc0000)
        libgcc_s_seh-1.dll =&gt; /mingw64/bin/libgcc_s_seh-1.dll (0x1a0000)
        libcairo-gobject-2.dll =&gt; /c/msys64/mingw64/bin/libcairo-gobject-2.dll (0x6cf40000)
        libgcc_s_seh-1.dll =&gt; /mingw64/bin/libgcc_s_seh-1.dll (0x1a0000)
        libfontconfig-1.dll =&gt; /c/msys64/mingw64/bin/libfontconfig-1.dll (0x64f80000)
        libpixman-1-0.dll =&gt; /c/msys64/mingw64/bin/libpixman-1-0.dll (0x63500000)
        libfreetype-6.dll =&gt; /c/msys64/mingw64/bin/libfreetype-6.dll (0x6aac0000)
        libpng16-16.dll =&gt; /c/msys64/mingw64/bin/libpng16-16.dll (0x68b40000)
        zlib1.dll =&gt; /mingw64/bin/zlib1.dll (0x62e80000)
        libepoxy-0.dll =&gt; /c/msys64/mingw64/bin/libepoxy-0.dll (0x6d880000)
        libfribidi-0.dll =&gt; /c/msys64/mingw64/bin/libfribidi-0.dll (0x66600000)
        libpangocairo-1.0-0.dll =&gt; /c/msys64/mingw64/bin/libpangocairo-1.0-0.dll (0x65880000)
        libpangowin32-1.0-0.dll =&gt; /c/msys64/mingw64/bin/libpangowin32-1.0-0.dll (0x676c0000)
        libffi-7.dll =&gt; /c/msys64/mingw64/bin/libffi-7.dll (0x71040000)
        libwinpthread-1.dll =&gt; /mingw64/bin/libwinpthread-1.dll (0x64940000)
        libpcre-1.dll =&gt; /mingw64/bin/libpcre-1.dll (0x69140000)
        libthai-0.dll =&gt; /c/msys64/mingw64/bin/libthai-0.dll (0x66880000)
        libatk-1.0-0.dll =&gt; /c/msys64/mingw64/bin/libatk-1.0-0.dll (0x6bd40000)
        libharfbuzz-0.dll =&gt; /c/msys64/mingw64/bin/libharfbuzz-0.dll (0x6f840000)
        libiconv-2.dll =&gt; /mingw64/bin/libiconv-2.dll (0x66000000)
        libexpat-1.dll =&gt; /mingw64/bin/libexpat-1.dll (0x68f40000)
        libbz2-1.dll =&gt; /mingw64/bin/libbz2-1.dll (0x626c0000)
        libbrotlidec.dll =&gt; /c/msys64/mingw64/bin/libbrotlidec.dll (0x6e440000)
        libgcc_s_seh-1.dll =&gt; /mingw64/bin/libgcc_s_seh-1.dll (0x1a0000)
        libpangoft2-1.0-0.dll =&gt; /c/msys64/mingw64/bin/libpangoft2-1.0-0.dll (0x6e7c0000)
        libdatrie-1.dll =&gt; /c/msys64/mingw64/bin/libdatrie-1.dll (0x68ac0000)
        libgraphite2.dll =&gt; /c/msys64/mingw64/bin/libgraphite2.dll (0x70540000)
        libstdc++-6.dll =&gt; /mingw64/bin/libstdc++-6.dll (0x6fc40000)
        libbrotlicommon.dll =&gt; /c/msys64/mingw64/bin/libbrotlicommon.dll (0x6d4c0000)
        libgcc_s_seh-1.dll =&gt; /mingw64/bin/libgcc_s_seh-1.dll (0x1a0000)</pre></td></tr></table></pre>
</div><br />
<font size="7">Construction de l'archive avec les ressources nécessaires</font><br />
<br />
Tout d'abord, veuillez récupérer et décompresser les dernières versions des icônes <a href="https://download.gnome.org/sources/adwaita-icon-theme/" target="_blank">Adwiata </a>et <a href="https://www.freedesktop.org/wiki/Software/icon-theme/" target="_blank">Hicolor</a>. Les icônes Adwaita sont déjà incluses, par contre il faudra compiler les icônes hicolor.<br />
<br />
Pour ce faire, avec le terminal msys, allez dans le dossier où vous avez décompressé l'archive hicolor. Et exécutez les commandes suivantes:<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
./autogen.sh
make .MAKE</pre></td></tr></table></pre>
</div>Soit $MSYS le dossier où est installé Msys2 (Par défaut C:\msys64 pour les installation 64 bits). Aussi pensez à adapter le dossier $MSYS/mingw64 en fonction de votre architecture.<br />
<br />
Nous allons archiver l'application et ses dépendances:<br />
<ul><li style="">Il faudra copier le contenu de $MSYS/mingw64/share/glib-2.0/schemas dans le dossier share/glib-2.0/schemas/ du dossier de préparation de l'archive</li><li style="">l'exécutable bien sûr</li><li style="">les dll listées par la commande ldd utilisée plus tôt dans le billet,</li><li style="">le sous-dossier icône Adwaita de l'archive Adwaita que vous avez récupéré et le dossier hicolor compilé (il se trouve dans $MSYS/mingw64/share/icons) dans le dossier share/icons/ du dossier de préparation de l'archive</li></ul><br />
<br />
Vous pouvez donc compresser le fichier, qui devrait normalement contenir toutes les dépendances.<br />
<br />
<br />
<font size="7">Conclusion</font><br />
<br />
Voilà, j'espère que cela a aussi fonctionné de votre côté :) .</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b9429/rust-windows-gtk-relm-deploiement-d-application-gtkprelm-sous-windows-approche-possible/</guid>
		</item>
		<item>
			<title><![CDATA[[Rust][AppImage][Docker][Linux] Création d'une AppImage à partir d'un binaire Rust avec Docker]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b9415/rust-appimage-docker-linux-creation-d-appimage-partir-d-binaire-rust-docker/</link>
			<pubDate>Thu, 21 May 2020 14:17:20 GMT</pubDate>
			<description>Bonjour, dans ce billet je...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Bonjour, dans ce billet je vais essayer de parler simplement de la création d'une AppImage pour un binaire graphique Rust GTK, en utilisant une image Docker en mode intéractif.<br />
<br />
<font size="5">Prérequis</font><br />
<br />
Pour pouvoir suivre ce billet, il est recommandé de connaître les bases de<br />
<ul><li style="">Rust: syntaxe de base, ownership/borrowing, struct/impl/enum, cargo, (juste pour comprendre les sources du projet si vous le souhaitez)</li><li style="">Gtk+Relm: les bases, j'ai présenté cette combinaison <a href="https://www.developpez.net/forums/blogs/26529-tails/b8921/rust-gtk-rs-relm-tutoriel-simple-application-saluant-l-utilisateur-prenom-qu-renseigne/" target="_blank">dans un billet précédent</a>,</li><li style="">Docker: création/exécution d'images, mode intéractif (tty), volumes,</li><li style="">Git: pour pouvoir récupérer les sources du projet &quot;cobaye&quot;</li><li style="">Commandes de bases dans un terminal linux: cd, ls, notamment. En effet, l'utilisation du terminal sera massive dans ce tutoriel.</li></ul><br />
<br />
<font size="5">Le format AppImage</font><br />
<br />
Il s'agit en quelque sortes d'un fichier compressée, <b>embarquant un programme et ses dépendances dynamiques</b> notamment, et qui se monte sur son propre systèmes de fichiers. Ce format tente donc de résoudre la problématique du déploiement d'application vis-à-vis de la fragmentation des nombreuses distributions Linux.<br />
<br />
Cependant, il est basé sur l'utilisation de l'utilitaire Fuse. Ce programme, disponible sous forme de paquets dans certaines distributions Linux (s'il n'est pas déjà installé par défaut), permet de monter un système de fichiers sans pour autant que l'on soit administrateur (root).<br />
<br />
<font size="5">Le programme &quot;cobaye&quot; et ses dépendances</font><br />
<br />
Pour effectuer notre expérimentation, nous allons compiler une calculatrice on ne peut plus simple et ridicule et qui, pour des raisons pratiques, n'a pas d'opérateur division.<br />
<br />
Veuillez cloner le projet dans le dossier de votre choix:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; git clone https://github.com/loloof64/SimpleCalculator.git calculatrice</pre></td></tr></table></pre>
</div>En examinant les sources et le fichier Cargo.toml, vous pouvez constater qu'il s'agit d'une application Gtk+Relm minimaliste.<br />
<br />
Veuillez compiler (et exécuter) le programme afin de pouvoir en analyser les dépendances dynamiques: (j'utilise la version 2018 de Rust, la dernière version à ce jour devrait convenir)<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; cargo run --release</pre></td></tr></table></pre>
</div>Si tout se passe bien, l'exécutable se trouve dans le sous-dossier target/release. Analysons-donc les dépendances dynamiques à l'aide de la commande ldd. Voici ce que cela a donné de mon côté:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; ldd target/release/simple-calc
        linux-vdso.so.1 (0x00007fff669c3000)
        libgtk-3.so.0 =&gt; /lib/x86_64-linux-gnu/libgtk-3.so.0 (0x00007f8a33d5c000)
        libgdk-3.so.0 =&gt; /lib/x86_64-linux-gnu/libgdk-3.so.0 (0x00007f8a33c58000)
        libpango-1.0.so.0 =&gt; /lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007f8a33c0c000)
        libcairo-gobject.so.2 =&gt; /lib/x86_64-linux-gnu/libcairo-gobject.so.2 (0x00007f8a33c00000)
        libcairo.so.2 =&gt; /lib/x86_64-linux-gnu/libcairo.so.2 (0x00007f8a33ae0000)
        libgdk_pixbuf-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x00007f8a33ab8000)
        libgio-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007f8a338db000)
        libgobject-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007f8a3387e000)
        libglib-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f8a33756000)
        libdl.so.2 =&gt; /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8a33750000)
        libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8a3372d000)
        libgcc_s.so.1 =&gt; /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8a33713000)
        libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8a33520000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8a344dd000)
        libgmodule-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007f8a3351a000)
        libpangocairo-1.0.so.0 =&gt; /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007f8a33509000)
        libX11.so.6 =&gt; /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f8a333cb000)
        libXi.so.6 =&gt; /lib/x86_64-linux-gnu/libXi.so.6 (0x00007f8a333b9000)
        libXfixes.so.3 =&gt; /lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f8a331b3000)
        libatk-1.0.so.0 =&gt; /lib/x86_64-linux-gnu/libatk-1.0.so.0 (0x00007f8a33187000)
        libatk-bridge-2.0.so.0 =&gt; /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0 (0x00007f8a33151000)
        libepoxy.so.0 =&gt; /lib/x86_64-linux-gnu/libepoxy.so.0 (0x00007f8a3301f000)
        libfribidi.so.0 =&gt; /lib/x86_64-linux-gnu/libfribidi.so.0 (0x00007f8a33002000)
        libm.so.6 =&gt; /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8a32eb3000)
        libharfbuzz.so.0 =&gt; /lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007f8a32dbc000)
        libpangoft2-1.0.so.0 =&gt; /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007f8a32da0000)
        libfontconfig.so.1 =&gt; /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f8a32d5a000)
        libfreetype.so.6 =&gt; /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f8a32c9f000)
        libXinerama.so.1 =&gt; /lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007f8a32c9a000)
        libXrandr.so.2 =&gt; /lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007f8a32c8d000)
        libXcursor.so.1 =&gt; /lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007f8a32c80000)
        libXcomposite.so.1 =&gt; /lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007f8a32c79000)
        libXdamage.so.1 =&gt; /lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f8a32c74000)
        libxkbcommon.so.0 =&gt; /lib/x86_64-linux-gnu/libxkbcommon.so.0 (0x00007f8a32c33000)
        libwayland-cursor.so.0 =&gt; /lib/x86_64-linux-gnu/libwayland-cursor.so.0 (0x00007f8a32c2a000)
        libwayland-egl.so.1 =&gt; /lib/x86_64-linux-gnu/libwayland-egl.so.1 (0x00007f8a32c25000)
        libwayland-client.so.0 =&gt; /lib/x86_64-linux-gnu/libwayland-client.so.0 (0x00007f8a32c14000)
        libXext.so.6 =&gt; /lib/x86_64-linux-gnu/libXext.so.6 (0x00007f8a32bfd000)
        librt.so.1 =&gt; /lib/x86_64-linux-gnu/librt.so.1 (0x00007f8a32bf2000)
        libthai.so.0 =&gt; /lib/x86_64-linux-gnu/libthai.so.0 (0x00007f8a32be7000)
        libpixman-1.so.0 =&gt; /lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007f8a32b40000)
        libpng16.so.16 =&gt; /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007f8a32b08000)
        libxcb-shm.so.0 =&gt; /lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007f8a32b01000)
        libxcb.so.1 =&gt; /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f8a32ad8000)
        libxcb-render.so.0 =&gt; /lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007f8a32ac9000)
        libXrender.so.1 =&gt; /lib/x86_64-linux-gnu/libXrender.so.1 (0x00007f8a328bf000)
        libz.so.1 =&gt; /lib/x86_64-linux-gnu/libz.so.1 (0x00007f8a328a3000)
        libmount.so.1 =&gt; /lib/x86_64-linux-gnu/libmount.so.1 (0x00007f8a32843000)
        libselinux.so.1 =&gt; /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f8a32816000)
        libresolv.so.2 =&gt; /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f8a327fb000)
        libffi.so.6 =&gt; /lib/x86_64-linux-gnu/libffi.so.6 (0x00007f8a327f1000)
        libpcre.so.3 =&gt; /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f8a3277d000)
        libdbus-1.so.3 =&gt; /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007f8a3272e000)
        libatspi.so.0 =&gt; /lib/x86_64-linux-gnu/libatspi.so.0 (0x00007f8a326f5000)
        libgraphite2.so.3 =&gt; /lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007f8a326c8000)
        libexpat.so.1 =&gt; /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f8a3269a000)
        libuuid.so.1 =&gt; /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007f8a32691000)
        libdatrie.so.1 =&gt; /lib/x86_64-linux-gnu/libdatrie.so.1 (0x00007f8a32687000)
        libXau.so.6 =&gt; /lib/x86_64-linux-gnu/libXau.so.6 (0x00007f8a3267f000)
        libXdmcp.so.6 =&gt; /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f8a32677000)
        libblkid.so.1 =&gt; /lib/x86_64-linux-gnu/libblkid.so.1 (0x00007f8a32620000)
        libpcre2-8.so.0 =&gt; /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f8a3259b000)
        libsystemd.so.0 =&gt; /lib/x86_64-linux-gnu/libsystemd.so.0 (0x00007f8a324f3000)
        libbsd.so.0 =&gt; /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f8a324d7000)
        liblzma.so.5 =&gt; /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f8a324b0000)
        liblz4.so.1 =&gt; /lib/x86_64-linux-gnu/liblz4.so.1 (0x00007f8a32490000)
        libgcrypt.so.20 =&gt; /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f8a32372000)
        libgpg-error.so.0 =&gt; /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f8a3234f000)</pre></td></tr></table></pre>
</div>Elles sont toutes résolues : c'est <b>la seule prérogative</b> pour pouvoir construire un fichier AppImage à partir du binaire.<br />
<br />
Nous pouvons donc passer à l'étape de la création du fichier AppImage. Pour cela je vais me servir de Docker, car il est recommandé de construire l'AppImage sur une version de linux assez ancienne afin qu'elle puisse ensuite s'exécuter sur la majorité des distributions existantes. Sans rentrer dans les détails, c'est notamment à cause de la libc.<br />
<br />
J'ai donc opté pour l'utilisation de Docker pour me faciliter la tâche, sachant que je pourrais monter un volume sur l'image docker afin de pouvoir partager des fichiers depuis mon système hôte.<br />
<br />
Sachez également que Travis CI (entre autres) permet de faire cela plus simplement depuis un repository Github, mais cela sort du cadre de ce billet.<br />
<br />
<font size="5">Construction avec Docker</font><br />
<br />
<font size="3">L'image personnalisée pour l’environnement de travail</font><br />
<br />
Tout d'abord, nous pouvons nous constituer une image Docker qui contiendra à minima l'installation de Rust et les utilitaires pour construire l'AppImage. Par la suite nous lancerons un conteneur basé sur cette image (que l'on pourra réutiliser à souhait), en mode intéractif, afin de construire l'AppImage<br />
<br />
Veuillez créer un conteneur basé sur la version 16.04 d'Ubuntu, en démarrant un bash en mode interactif:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; docker run -t -i --name ubuntu_16_rust_setup ubuntu:16.04 /bin/bash</pre></td></tr></table></pre>
</div>Voici la liste des commandes à entrer, une à une, une fois que le conteneur a démarré (attention à ne pas insérer mes commentaires :lol:):<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
apt update
apt install wget curl git fuse build-essential libgtk-3-dev -y
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # installation de Rust : veuillez chosir l'option par défaut
exit</pre></td></tr></table></pre>
</div>De retour dans votre terminal hôte (grâce à la commande exit), veuillez transformer le conteneur juste créé en image:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; docker commit ubuntu_16_rust_setup ubuntu_16_rust:v1</pre></td></tr></table></pre>
</div>Comme précisé plus haut, cette image pourra être réutilisée plusieurs fois.<br />
<br />
<font size="3">Construction de l'AppImage</font><br />
<br />
Nous pouvons donc démarrer un conteneur à partir de notre base de travail:<br />
<ul><li style="">j'utilise encore le mode intéractif</li><li style="">je monte un volume me permettant d'accéder aux ressources que j'ai préparées pour mon projet (fichier desktop, icone): ici avec le dossier courant ($PWD)</li><li style="">j'indique également quelques drapeaux supplémentaires afin de pouvoir créer l'AppImage sans tracas</li><li style="">ce conteneur sera détruit (--rm) en le quittant : vous pouvez en décider autrement si vous le souhaitez (c'est juste dans mon utilisation personnelle, j'ai trouvé cela plus pratique)</li></ul><br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; docker run -t -i -v &quot;$PWD:/home/host_documents&quot; --cap-add SYS_ADMIN --cap-add MKNOD --device=/dev/fuse --security-opt apparmor:unconfined --rm ubuntu_16_rust:v1 /bin/bash</pre></td></tr></table></pre>
</div><font size="1">Préparatifs côté hôte</font><br />
<br />
Avant de commencer la construction de l'AppImage, préparons les ressources nécessaires, que nous placerons dans le dossier hôte sur lequel nous avons monté notre image de travail:<br />
<ul><li style="">un fichier .desktop : je vous passe le contenu du mien plus bas</li><li style="">une icône png (la taille 16x16 peut faire l'affaire)</li><li style="">le script qui nous simplifiera la tâche, je vous en passe le contenu plus bas</li></ul><br />
<br />
Voici un fichier .desktop (SimpleCalc.desktop) que vous pouvez utiliser:<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">
[Desktop Entry]
Version=1.0
Type=Application
Name=Simple calculator
Comment=A ridiculously simple calculator
Exec=simple-calc
Icon=calculator
Categories=Utility;Education;</pre></td></tr></table></pre>
</div>Il requiert donc que l'icône utilisée s'appelle calculator.png.<br />
<br />
Voici le script que nous utiliserons dans le conteneur (build_appimage.sh) :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td valign="top"><pre style="margin: 0">
#!/bin/bash

##############################################################
# Building exectuable into AppImage (Laurent Bernabe)        #
# from an Ubuntu 14.04 x86_64 docker image.                  #
#                                                            #
# Also these arguments are needed when lauching docker run ! #
# --cap-add SYS_ADMIN                                        #
# --cap-add MKNOD                                            #
# --device=/dev/fuse                                         #
# --security-opt apparmor:unconfined                         #
#                                                            #
# Volume /home/host_documents should point to                #
# the build files folder !                                   #
#                                                            #
# Arguments:                                                 #
# 1 =&gt; Path to AppImage target (with AppImage extension)     #
# 2 =&gt; Path to executable to wrap                            #
# 3 =&gt; Desktop file name (with .desktop extension)           #
# 4 =&gt; Icon file name (with extension)                       #
##############################################################

if [[ &quot;$#&quot; -lt 4 ]]; then
    echo &quot;Usage: build_appimage TARGET_APPIMAGE EXECUTABLE DESKTOP_FILE ICON_FILE&quot;
    exit 1
fi


apt update
apt install wget fuse file -y

wget -P /tmp https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -P /tmp https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x /tmp/linuxdeploy-x86_64.AppImage /tmp/appimagetool-x86_64.AppImage
cd /home/host_documents

/tmp/linuxdeploy-x86_64.AppImage -e $2 -d $3 -i $4 --appdir $1
/tmp/appimagetool-x86_64.AppImage $1

exit 0</pre></td></tr></table></pre>
</div>Notamment, ce script:<br />
<ol class="decimal"><li style="">Télécharge les deux utilitaires necessaires à la création d'AppImage à partir d'un binaire existant,</li><li style="">construit un dossier AppImage à partir de l'exécutable et de ses ressources,</li><li style="">construit une archive AppImage à partir du dossier ainsi généré.</li></ol><br />
<br />
<font size="1">Etape finale</font><br />
<br />
Allons-y !<br />
<br />
Rendons les commandes de Rust disponibles:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; source $HOME/.cargo/env</pre></td></tr></table></pre>
</div>Crééons un dossier projets:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; mkdir -p /home/projects
$&gt; cd /home/projects</pre></td></tr></table></pre>
</div>Clonons le projet et compilons-le:<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; git clone https://github.com/loloof64/SimpleCalculator.git calculatrice
$&gt; cd calculatrice
$&gt; cargo build --release</pre></td></tr></table></pre>
</div>Enfin passons à la production de l'AppImage, en n'oubliant pas de renseigner les différents paramètres<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
$&gt; cd /home/host_documents
$&gt; chmod +x build_appimage.sh
$&gt; ./build_appimage.sh SimpleCalculator.AppImage /home/projects/calculatrice/target/release/simple-calc ./SimpleCalc.desktop ./calculator.png</pre></td></tr></table></pre>
</div>Normalement vous devriez disposer du fichier AppImage dans votre dossier monté sur le système hôte. N'oubliez pas de quitter le conteneur<br />
<br />
<font size="5">Conclusion</font><br />
<br />
Voilà en ce qui concerne la création de l'AppImage, j'espère que cela n'a pas été indigeste.<br />
Vous avez donc la possibilité de tester le programme sur différentes distributions Linux. Sachez que pour ma part, j'ai réussi à l'exécuter sur des distributions Ubuntu (Ubuntu, Kubuntu, Xubuntu), Gentoo, Manjaro Linux, Linux Mint datant de 2016/2017 et même 2020 entre autres.<br />
<br />
Je tiens quand même à remercier les contributeurs des projets relatifs à AppImageKit, qui m'ont gentiment répondu à mes interrogations sur leur chat Irc : en particulier TheNinjaAssasin.</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b9415/rust-appimage-docker-linux-creation-d-appimage-partir-d-binaire-rust-docker/</guid>
		</item>
		<item>
			<title><![CDATA[[Rust][Gtk-Rs][Relm][tutoriel] Une simple application saluant l'utilisateur par son prénom (qu'il renseigne)]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b8921/rust-gtk-rs-relm-tutoriel-simple-application-saluant-l-utilisateur-prenom-qu-renseigne/</link>
			<pubDate>Wed, 05 Feb 2020 18:38:21 GMT</pubDate>
			<description><![CDATA[Le "crate" Relm...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Le <a href="https://crates.io/crates/relm" target="_blank">&quot;crate&quot; Relm</a> est une librairie visant à simplifier la création d'applications GTK en Rust en permettant d'utiliser une syntaxe déclarative.<br />
Afin de mettre le pied à l'étrier, j'ai décidé de réaliser une application minimaliste, où le but est simplement de saluer l'utilisateur par le prénom qu'il a renseigné.<br />
<br />
<img src="https://www.developpez.net/forums/attachments/p536095d1580900290/general-developpement/debats-developpement-best-of/web-contre-client-serveur-choisir/apercu_saluer_utilisateur.png/" border="0" alt="Nom : apercu_saluer_utilisateur.png
Affichages : 1290
Taille : 17,5 Ko"  style="float: CONFIG" /><br />
<br />
Tout d'abord, afin de pouvoir suivre ce billet, vous devez<br />
<ul><li style="">connaître un minimum le fonctionnement de Rust, les modules, l'utilitaire Cargo, ainsi que les bases des Structs/Traits/Impl,</li><li style="">connaître les bases du développement en Gtk, même par le biais d'un autre langage (tel que Python). En effet, les connaissances peuvent être transposées.</li></ul><br />
<br />
<font size="6">Configuration des dépendances</font><br />
<br />
Après avoir créé un nouveau projet binaire <div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">cargo new $nom_projet</pre>
</div> (remplacer $nom_projet par le nom voulu) nous pouvons ajouter la courte liste de dépendances dans le fichier Cargo.toml<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
gtk = &quot;0.7.0&quot;
relm = &quot;0.18.0&quot;
relm-derive = &quot;0.18.0&quot;</pre></td></tr></table></pre>
</div><font size="6">Ajout du code et exécution</font><br />
<br />
<font size="4">Module d'interface</font><br />
<br />
Nous pouvons ajouter le code graphique, que j'expliquerais plus bas, dans un fichier gui.rs, directement dans le sous-dossier src.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Rust :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">use</span> relm::Widget;
<span style="color: #0000ff;">use</span> relm_derive::<span class="br0">&#123;</span>Msg, widget<span class="br0">&#125;</span>;
&nbsp;
<span style="color: #0000ff;">use</span> gtk::<span class="br0">&#123;</span>LabelExt, WidgetExt, Inhibit, OrientableExt, EntryExt<span class="br0">&#125;</span>;
&nbsp;
<span style="color: #339933;">#</span><span style="color: #339933;"><span class="br0">&#91;</span>derive<span class="br0">&#40;</span>Msg<span class="br0">&#41;</span><span class="br0">&#93;</span></span>
<span style="color: #0000ff;">pub</span> <span style="color: #0000ff;">enum</span> AppMsg <span class="br0">&#123;</span>
    Ignore,
    Quit,
    UpdateMessage<span class="br0">&#40;</span>String<span class="br0">&#41;</span>,
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">pub</span> <span style="color: #0000ff;">struct</span> AppModel <span class="br0">&#123;</span>
    message: String,
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #339933;">#</span><span style="color: #339933;"><span class="br0">&#91;</span>widget<span class="br0">&#93;</span></span>
<span style="color: #0000ff;">impl</span> Widget <span style="color: #0000ff;">for</span> AppWindow <span class="br0">&#123;</span>
    <span style="color: #0000ff;">fn</span> model<span class="br0">&#40;</span><span class="br0">&#41;</span> -&gt; AppModel <span class="br0">&#123;</span>
        AppModel <span class="br0">&#123;</span>
            message: String::from<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Bonjour le monde !&quot;</span><span class="br0">&#41;</span>,
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">fn</span> update<span class="br0">&#40;</span>&amp;<span style="color: #0080ff;">mut</span> <span style="color: #FF0000;">self</span>, event: AppMsg<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span style="color: #0000ff;">match</span> event <span class="br0">&#123;</span>
            AppMsg::Ignore =&gt; <span class="br0">&#123;</span><span class="br0">&#125;</span>,
            AppMsg::Quit =&gt; gtk::main_quit<span class="br0">&#40;</span><span class="br0">&#41;</span>,
            AppMsg::UpdateMessage<span class="br0">&#40;</span>name<span class="br0">&#41;</span> =&gt; <span style="color: #FF0000;">self</span>.update_hello_message<span class="br0">&#40;</span>name<span class="br0">&#41;</span>,
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">fn</span> update_hello_message<span class="br0">&#40;</span>&amp;<span style="color: #0080ff;">mut</span> <span style="color: #FF0000;">self</span>, name: String<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span style="color: #FF0000;">self</span>.model.message = <span style="color: #0080ff;">format!</span><span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Bonjour <span style="color: #800000;">{}</span> !&quot;</span>, name<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0080ff;">view!</span> <span class="br0">&#123;</span>
        gtk::Window <span class="br0">&#123;</span>
            gtk::Box <span class="br0">&#123;</span>
                orientation: gtk::Orientation::Vertical,
                gtk::Box <span class="br0">&#123;</span>
                    orientation: gtk::Orientation::Horizontal,
                    gtk::Label <span class="br0">&#123;</span>
                        text: <span style="color: #FF0000;">&quot;Votre pr&eacute;nom: &quot;</span>,
                    <span class="br0">&#125;</span>,
                    <span style="color: #339933;">#</span><span style="color: #339933;"><span class="br0">&#91;</span>name=<span style="color: #FF0000;">&quot;name_input&quot;</span><span class="br0">&#93;</span></span>
                    gtk::Entry <span class="br0">&#123;</span>
                        text: <span style="color: #FF0000;">&quot;le monde&quot;</span>,
                        activate<span class="br0">&#40;</span>text_comp<span class="br0">&#41;</span> =&gt; <span style="color: #0000ff;">match</span> text_comp.get_text<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
                            <span style="color: #FF0000;">Some</span><span class="br0">&#40;</span>name<span class="br0">&#41;</span> =&gt; AppMsg::UpdateMessage<span class="br0">&#40;</span>String::from<span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="br0">&#41;</span>,
                            <span style="color: #FF0000;">None</span> =&gt; AppMsg::Ignore,
                        <span class="br0">&#125;</span>,
                    <span class="br0">&#125;</span>
                <span class="br0">&#125;</span>,
                gtk::Label <span class="br0">&#123;</span>
                    text: &amp;<span style="color: #FF0000;">self</span>.model.message.to_owned<span class="br0">&#40;</span><span class="br0">&#41;</span>,
                <span class="br0">&#125;</span>,
            <span class="br0">&#125;</span>,
            delete_event<span class="br0">&#40;</span>_self, _event<span class="br0">&#41;</span> =&gt; <span class="br0">&#40;</span>AppMsg::Quit, Inhibit<span class="br0">&#40;</span><span style="color: #FF0000;">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span>,
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">pub</span> <span style="color: #0000ff;">fn</span> run_app<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    AppWindow::run<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.expect<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Echec de demarrage de l'application&quot;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
<font size="4">La fonction main</font><br />
<br />
Nous pouvons modifier le fichier main.rs ainsi :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Rust :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:132px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">mod</span> gui;
&nbsp;
<span style="color: #0000ff;">use</span> gui::run_app;
&nbsp;
<span style="color: #0000ff;">fn</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    run_app<span class="br0">&#40;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
L'application devrait donc pouvoir compiler et fonctionner <div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">cargo run</pre>
</div><font size="6">Fonctionnement général de Relm</font><br />
<br />
Avant d'expliquer le fonctionnement du code exemple, il nous faut d'abord comprendre comment fonctionne la librairie Relm de manière générale.<br />
<br />
En Relm, on peut considérer que chaque composant est le reflet d'un modèle (des données qu'il est censé gérer), qui reçoit des messages en guise d’événements, et met à jour sa vue (son interface graphique) en fonction de ces messages. Une application Relm est constituée d'au moins un composant : le composant qui gère la fenêtre principale (et qui donc aura un gtk::Window comme composant racine).<br />
<br />
Dans ce billet, nous voyons comment construire un composant en utilisant des attributs Rust (#[widget] entre autres) qui génère le code correspondant, mais sachez qu'il est également possible de s'en passer et de ne faire qu'avec du code. Pour cela, je vous invite à consulter <a href="https://github.com/antoyo/relm/tree/master/relm-examples" target="_blank">les exemples officiels</a> (ceux qui ne se terminent pas par &quot;-attribute.rs&quot;).<br />
<br />
Ainsi dans notre exemple :<br />
<ul><li style="">le model (AppModel) est constitué d'un unique champ message (String),</li><li style="">l'énumération AppMessages définit l'ensemble des messages possibles pour le composant associé AppWindow. A noter l'utilisation de l'attribut #[derive(Msg)] et d'un Tuple Struct UpdateMessage acceptant une String en paramètre,</li><li style="">l'implémentation AppWindow permet de définir le composant. A noter l'utilisation de l'attribut #[widget] qui générera la classe composant.</li></ul><br />
<br />
La classe AppWindow définit également deux méthodes de base de tout composant :<br />
<ul><li style="">fn model() -&gt; AppModel, chargé de définir la valeur initiale du model associé au composant. Ici nous retournons une instance de la structure AppModel que nous avons défini plus haut. Mais nous aurions pu lui associer une autre structure,</li><li style="">fn update(&amp;mut self, event: AppMsg) qui doit mettre à jour le modèle en fonction du message reçu. De même, nous aurions pu associer une autre énumération utilisant l'attribut #[derive(Msg)].</li></ul><br />
<br />
Et enfin, la macro view! permet de définir l'apparence graphique du composant. Et comme nous le verrons plus bas, nous pouvons simplement définir les propriétés des composants et Widgets GTK déclarés dans cette hiérarchie (notamment certaines en fonction du modèle associé au composant), ainsi que de lier des événements aux messages que nous avons définis. Pour rappel, on doit se contenter d'envoyer des messages, et c'est la méthode update qui met à jour le modèle, qui lui-même déclenchera une mise à jour de la vue s'il change.<br />
<br />
Maintenant, il est tant d'essayer de mieux comprendre le fonctionnement de notre projet.<br />
<br />
<font size="6">Décortiquons notre code</font><br />
<br />
<font size="4">Le module graphique gui.rs</font><br />
<br />
Lignes 2 et 3, nous importons quelques éléments utiles des modules relm et relm-derive : l'attribut widget, le trait Widget et le type Msg.<br />
<br />
Ligne 5, nous importons divers traits de la librairie Gtk ainsi que la structure Inhibit. La structure Inhibit est utilisé pour gérer l'évènement Quit du composant, comme nous le verrons plus loin. Tandis que les différents traits suffixés par Ext sont des traits définissant différentes fonctionnalités des Widgets Gtk utilisés par notre composant. Par exemple, LabelExt apporte certaines fonctionnalités au Widget Label : dont notamment la méthode set_text(). Autre exemple, le trait OrientableExt permet de définir l'orientation de certains widgets, via la méthode set_orientation(), dont le Widget Box.<br />
Alors comment savoir quel trait apporte quelle fonctionnalité ? Il suffit, dans <a href="https://gtk-rs.org/docs/gtk/" target="_blank">la documentation de Gtk-Rs</a>, de rechercher la documentation correspondant au Widget voulu, prenons par exemple le Widget gtk::Button. Nous avons donc accès à la section <i>Implements</i>, listant les différents traits implémentés par le Widget, et de naviguer dans les différentes documentations de ces traits. Ainsi, en naviguant dans la documentation de ButtonExt par exemple, nous retrouvons entre autres la méthode connect_clicked : permettant de gérer l’événement clic.<br />
<br />
Lignes 7 à 12: les différents messages que nous souhaitons voir gérer par notre composant, et qui mettra à jour le modèle en conséquence. Quand un message a besoin de paramètres, on peut facilement définir un Tuple Struct, tout comme nous l'avons fait pour UpdateMessage. Le nom de l'énumération est évidemment libre.<br />
<br />
Lignes 14 à 16: le modèle de notre composant : ici nous souhaitons juste gérer le message destiné à l'utilisateur.<br />
<br />
Lines 18 et 19: pour définir notre composant, nous implémentons le trait Widget, sans oublier de préciser l'attribut #[widget], le nom de la structure étant encore une fois, libre.<br />
<br />
Lignes 20 à 24: la définition du modèle initial pour notre composant.<br />
<br />
Lignes 26 à 32: la mise à jour du composant, ou plutôt de son modèle, en fonction des messages reçus. Nous utilisons un simple pattern matching sur le type du message. Nous avons aussi bien fait directement appel à du code Gtk, gtk::main_quit() pour quitter l'application, que fait appel à une méthode personnelle pour du traitement plus complexe (update_hello_message(name)). Il est également possible de ne rien associer au message, comme pour le message Ignore.<br />
<br />
Lignes 38 à 62: la définition de l'interface par l'intermédiaire de la macro view!. Les éléments y sont imbriquées, chaque propriété/événement/composant ou widget enfant étant séparé par une virgule. Il faut alors distinguer propriété et événement.<br />
<br />
Les propriétés sont définis par toute méthode préfixée par set_ dans l'ensemble des Traits décorant les Widgets Gtk, comme expliqué plus haut (les différentes classes suffixées par Ext). Ainsi le trait LabelExt, que le Widget Label implémente, définit une méthode set_text(). Nous pouvons donc utiliser la propriété text sur le Widget Label, comme en ligne 57. Pour définir une propriété d'un composant, on supprime donc le préfixe set_ ainsi que les parenthèses, et nous définissons la valeur après le signe de ponctuation deux points &quot;:&quot;. Un autre exemple de propriété: orientation pour le widget gtk::Box, ligne 43.<br />
<br />
Les évènements sont définis par toute méthode préfixée par connect_ dans l'ensemble des Traits décorant les Widgets Gtk. Ainsi, le trait EntryExt, implémenté notamment par la structure Entry, définit la méthode connect_activate. Cet évènement permet de gérer la validation de la valeur du champ texte par la touche Enter. Nous pouvons voir cela à l'oeuvre en ligne 50. Ainsi, pour définir un évènement nous enlevons le préfixe connect_, puis ajoutons les paramètres en donnant des noms arbitraires, car cela fonctionne avec le pattern matching. Ensuite il faut ajouter le signe égal suivi du signe supérieur &quot;=&gt;&quot;. Et enfin, nous définissons le message à envoyer au composant. Attention ! Les paramètres sont définis, dans la documentation, dans le paramètre Fn. Par exemple &quot;fn connect_activate&lt;F: Fn(&amp;Self) + 'static&gt;(&amp;self, f: F) -&gt; SignalHandlerId&quot;, l'évènement est activate, le paramètre &amp;self (Fn(<font color="#FF0000">&amp;self</font>)), donc on écrira activate(comp) =&gt; $handler, par exemple, ou même activate(_) =&gt; $handler. Où $handler est le code de votre gestionnaire pour cet évènement.<br />
<br />
Ainsi lignes 50 à 53, l’événement Activate du widget Entry est lié au message UpdateMessage en cas de succès de récupération de la valeur du champ texte, ou à Ignore en cas d'échec divers.<br />
<br />
Par contre, ligne 60, pour l'événement delete_event() de la fenêtre principale, nous retournons un Tuple dont le 1er paramètre est le type de message (ici Quit) et le deuxième paramètre est la valeur de retour attendue par l'évènement delete_event. En effet, si vous consultez la documentation de connect_delete_event, du trait WidgetExt (implémenté par gtk::Window), vous verrez qu'il faut retourner une valeur Inhibit. En effet la méthode est défini comme suit<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
fn connect_delete_event&lt;F: <font color="#FF0000">Fn(&amp;Self, &amp;Event) -&gt; Inhibit + 'static</font>&gt;(
    &amp;self,
    f: F
) -&gt; SignalHandlerId</pre></td></tr></table></pre>
</div>(J'ai mis en évidence ce qui nous intéresse vraiment.)<br />
Cette valeur sert à déterminer si les gestionnaires par défauts de l'événement restent actifs ou non. Même si la documentation recommande de ne pas les désactiver (donc de passer Inhibit(false)), il est possible de les désactiver (Inhibit(true)).<br />
<br />
Lignes 65 à 67: cette méthode nous permet d'appeler simplement le code d’exécution de l'application dans la fonction main. En effet, le code qu'elle contient doit être définit dans la même &quot;portée&quot; que la définition de notre composant, macro de génération oblige.<br />
<br />
<font size="4">Le code principal main.rs</font><br />
<br />
Ici rien de bien compliqué, grâce notamment à la définition de la méthode run_app dans le module gui.rs .<br />
<br />
<font size="6">Conclusion</font><br />
<br />
Dans ce tutoriel, nous avons vu une utilisation basique du framework Relm, dont le but est simplifier la création d'applications GTK en Rust.<br />
J'espère que ce billet n'a pas été trop indigeste.<br />
<br />
Je voudrais remercier <i>antoyo</i>, l'auteur du framework, pour ses précieuses réponses à mes questions sur <a href="https://gitter.im/relm-rs/Lobby" target="_blank">le forum Gitter dédié à Relm</a>.</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b8921/rust-gtk-rs-relm-tutoriel-simple-application-saluant-l-utilisateur-prenom-qu-renseigne/</guid>
		</item>
		<item>
			<title>Le langage Rust : ma nouvelle cible pour développer des applications de bureau :)</title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b6655/langage-rust-nouvelle-cible-developper-applications-bureau/</link>
			<pubDate>Fri, 30 Nov 2018 13:31:15 GMT</pubDate>
			<description>Cela fait quelques années que...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Cela fait quelques années que je suis de près ou de loin le langage de Mozilla : mais en ayant &quot;abandonné&quot; à plusieurs reprises. Toutefois, j'ai décidé de m'y remettre sérieusement depuis quelques semaines : fort des évolutions positives du langage, et d'une plus grande facilité en ce qui me concerne pour l'étudier plus profondément.<br />
<br />
Justement, je me suis lancé pour défi de développer <a href="https://github.com/loloof64/ChessPositionsTrainerPC" target="_blank">une application pour les 3 OS principaux</a> en Rust et Gtk. Et même si elle n'est encore qu'à ses balbutiements, je dois dire que je prends de plus en plus de plaisir à la développer. De plus <a href="https://gitter.im/rust-lang/rust" target="_blank">le canal de chat Rust sur Gitter</a> est très accueillant, toujours prêt à aider et à expliquer les concepts difficiles.<br />
<br />
Bref, j'ai également pu me rendre compte, moyennant quelques prises de têtes, combien il peut être aisé de développer une application depuis un environnement Linux, la publier sur Github, et ensuite la récupérer très simplement et la faire tourner sur Windows. La <a href="https://gtk-rs.org/" target="_blank">documentation officielle de Gtk-Rs</a> expliquant correctement la démarche quant aux prérequis pour installer Gtk sous Windows (Je suis passé, non par l'utilitaire MinGW, mais par CygWin).<br />
<br />
De plus, l'application fonctionne aussi bien en mode Debug qu'en mode Release (les ressources images sont le point critique).<br />
<br />
Pour finir, voici <a href="https://blog.rust-lang.org/2018/11/27/Rust-survey-2018.html" target="_blank">des résultats très intéressants d'un sondage Rust</a> anglophone.<br />
<br />
Voilà, en espérant que vous avez eu plaisir à lire ce billet</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b6655/langage-rust-nouvelle-cible-developper-applications-bureau/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Déclarations/Types/Inférence de types]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3685/kotlin-declarations-types-inference-types/</link>
			<pubDate>Tue, 05 Sep 2017 10:04:37 GMT</pubDate>
			<description>_Déclarations_ 
 
Comme vous...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><u>Déclarations</u><br />
<br />
Comme vous l'avez probablement constaté dans les billets précédents, en Kotlin lors d'une déclaration de variable (val ou var) on précise dans l'ordre :<br />
<ol class="decimal"><li style="">son immutabilité (val ou var ?) : pour rappel, val désigne une <b>val</b>eur fixée, donc immuable. Alors que var désigne une <b>var</b>iable donc muable</li><li style="">son nom : comme en Java, soumis à des restrictions et de plus limité par l'existence de mots-clés propres à Kotlin</li><li style="">son type : nous allons y venir très vite</li></ol><br />
<br />
(Bien sûr dans le cas où l'on utilise pas l'inférence de type, point sur lequel je reviendrais vite fait plus tard dans ce billet).<br />
<br />
Ainsi l'on peut écrire :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
var loopCount:Int = 5
val student55 = Student(firstName = &quot;John&quot;, lastName = &quot;Doe&quot;, age = 36) // Petit spoiler sur la création de classes :p</pre></td></tr></table></pre>
</div><u>Les Types</u><br />
<br />
<b>Le type logique : Boolean</b><br />
<br />
Tout d'abord, première remarque, le type Boolean prend une majuscule en Kotlin. Cela sera aussi le cas avec les autres types de Java -qui étaient primitifs en Java et ne le sont plus en Kotlin : le fameux &quot;tout est objet&quot;- qui prenaient une minuscule : Int, Float, Double, Long, Short, Byte.<br />
<br />
Rien de nouveau à part cela : true/false sont les deux valeurs possibles, et les opérateurs &amp;&amp;/||/! fonctionnent de la même manière qu'en Java. Vous ne devriez pas être embêté par l'utilisation des Boolean.<br />
<br />
<b>Les types numériques</b><br />
<br />
Int, Short, Byte, Long, Float, Double : presque comme en Java, hormis la majuscule.<br />
<br />
Déjà, commençons par un détail subtil : la conversion automatique en Wrapper ou primitif par le compilateur Kotlin. En effet, Kotlin essaiera dans la mesure du possible, pour des raisons de performances, de convertir la valeur en type purement primitif, et non en Wrapper. Mais dans certains cas cela sera impossible, par exemple pour l'utilisation de Générics.<br />
<br />
Ensuite, la taille mémoire est la même qu'en Java pour chacun des types. (Vérifiez d'ailleurs <a href="https://kotlinlang.org/docs/reference/basic-types.html#numbers" target="_blank">par vous-même</a>).<br />
<br />
Les littéraux sont semblables à Java : 12 est un Int, 12L est une Long, 123_456_789 est autorisé.<br />
<br />
Détail très important, si ce n'est le plus important de cette section : <b><u><font color="#FF0000">il n'y a aucune conversion automatique entre les différents types !</font></u></b> (Aucune coercition ni promotion).<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
val a:Int = 120L.toInt() // ok
// val b:Int = 120L // =&gt;  erreur de compilation !!!
val c:Long = 120 // fonctionne grâce à l'inférence de type !
// val d:Long = a // =&gt;  erreur de compilation !!!</pre></td></tr></table></pre>
</div>Enfin, les opérateurs de manipulation de bits de Java sont remplacés par des fonctions en Kotlin:<br />
<ul><li style="">shl : équivalent de &lt;&lt; (<b>sh</b>ift <b>l</b>eft)</li><li style="">shr : équivalent de &gt;&gt; (<b>sh</b>ift <b>r</b>ight)</li><li style="">ushr: équivalent de &gt;&gt;&gt; (<b>u</b>n<b>sh</b>ift <b>r</b>ight)</li><li style="">and()/or()/xor() : équivalents respectifs de &amp;/|/^</li><li style="">inv() : inversion de bits</li></ul><br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
val x = (1 shl 2) and 0x000FF000</pre></td></tr></table></pre>
</div><br />
<b>Les type &quot;Littéraires&quot;</b><br />
<br />
*)Le type Char : pas de difficulté particulière, si ce n'est que convertir un Char vers Int et inversement n'est pas automatique<br />
<br />
*)Le type String<br />
Tout d'abord il y a une nouvelle façon de déclarer une String, qui convient au format multilignes :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
&quot;&quot;&quot;
Mon
texte
multi lignes
&quot;&quot;&quot;</pre></td></tr></table></pre>
</div>Attention ! <u><font color="#FF0000">Ce format n'échappe pas les caractères spéciaux !</font></u><br />
En revanche, si la chaîne est agrémentée d'indentations pour une meilleure mise en forme, voici comment y remédier :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
println(&quot;&quot;&quot;|Voici
        |une simple
        |façon de traiter
        |une chaine multi lignes.
    &quot;&quot;&quot;.trimMargin())</pre></td></tr></table></pre>
</div>Enfin, une fonctionnalité très utile, les templates : elles fonctionnent d'ailleurs aussi bien avec le format standard que le format multi-lignes.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
val name = &quot;Cora&quot;
val age = 10

println(&quot;$name a $age an(s)&quot;)</pre></td></tr></table></pre>
</div>Ou encore, adaptons le pluriel de l'âge :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">
val name = &quot;Cora&quot;
val age = 10

println(&quot;$name a $age an${if (age &gt; 1) &quot;s&quot; else &quot;&quot;}&quot;)</pre></td></tr></table></pre>
</div><b>Le type range</b><br />
<br />
Qui n'a jamais trouvé laid de devoir sans cesse écrire un code de ce genre en Java ?<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
if (c &gt;= 0 &amp;&amp; c &lt;= 10)  { // instructions }</pre></td></tr></table></pre>
</div>ou encore<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
for (int i=0; i&lt;=10; i++) { // instructions }</pre></td></tr></table></pre>
</div>C'est là qu'en Kotlin on peut faire intervenir le type Range (Intervalle) :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
if (c in 0..10) { // instructions } // teste si c est supérieur et égal à 0 et inférieur et égal à 10</pre></td></tr></table></pre>
</div>De même<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
(0..10).forEach { i -&gt; // instructions impliquant i }</pre></td></tr></table></pre>
</div>Ce code fait intervenir une lambda (fonction anonyme), que nous aurons l'occasion d'étudier ultérieurement.<br />
<br />
N'oublions pas le mot-clé when :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
when(x_avion) {
   in 0..10, in 20..30 -&gt; &quot;L'attérissage est râté&quot; // teste si x_avion est ou bien dans 0..10 ou dans 20..30
   in 11..19 -&gt; &quot;L'attérissage est réussi&quot;
   else -&gt; &quot;Vous êtes sûr que l'on joue au même jeu ?&quot;
}</pre></td></tr></table></pre>
</div><u>Inférence de types</u><br />
<br />
Vous en avez déjà vu dans les billets précédents, j'ai beaucoup tendance à m'en servir :)<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val x = 120 // le compilateur a déduit que x est un Int
val x:Long = 120 // en revanche, le compilateur a déduit que le littéral 120 est à convertir en Long, et comme c'est possible, ça passe.</pre></td></tr></table></pre>
</div>L'inférence de type désigne toutes les situations où l'on ne déclare pas le type mais que le compilateur parvient à déduire du contexte.<br />
Je n'ai pas encore abordé les fonctions/méthodes, mais ça fonctionne aussi dans ce cas :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
fun Hello() = &quot;Hello, World !&quot;</pre></td></tr></table></pre>
</div>équivaut à<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
fun Hello():String {
    return &quot;Hello, World !&quot;
}</pre></td></tr></table></pre>
</div>Dans le premier cas le compilateur a juste déduit que le type de retour est String grâce à l'expression à droite de la déclaration de fonction.<br />
<br />
Sachez également que les Closures/Lambdas - qui n'ont pas été abordées - peuvent aussi utiliser l'inférence de type.<br />
<br />
Ouf ! Cela fait beaucoup d'informations dans ce billet, même si je n'ai évoqué que des bases.<br />
J'espère que vous avez pris du plaisir à lire ce billet :)</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3685/kotlin-declarations-types-inference-types/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Expressions]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3667/kotlin-expressions/</link>
			<pubDate>Sat, 02 Sep 2017 07:01:50 GMT</pubDate>
			<description>Comme en Java, en Kotlin tout...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Comme en Java, en Kotlin tout ce qui retourne une valeur est une expression : litéral, opération, appel de fonction ...<br />
On peut aussi combiner déclaration et expressions :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">
val a = 10
val b = f(150)
val c = 60*89</pre></td></tr></table></pre>
</div>Là où les choses deviennent intéressantes, c'est l'emploi de certaines structures de contrôles en tant qu'expressions !!!<br />
Je m'explique. Prenons le snippet suivant :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
val majeur = if (age &lt; 18) &quot;Non&quot; else &quot;Oui&quot;</pre></td></tr></table></pre>
</div>N'y remarquez-vous rien d'étrange ?<br />
<br />
Et oui, la structure de contrôle if est bien utilisée comme expression afin d'initialiser la variable majeur. D'ailleurs, au passage, il n'y a pas d'opérateur ternaire en Kotlin : cette syntaxe remplace l'opérateur ternaire.<br />
<br />
D'ailleurs je vous ferais remarquer que dans le cas de blocs en lieu et place des branches, la valeur de chaque branche correspond à la valeur de sa dernière ligne (et donc Unit -équivalent de Void- si jamais cette dernière ligne ne retourne aucune valeur) :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">
val majeur = if (age &lt; 18) {
   println(&quot;Non, accès interdit !&quot;)
   false
}
else {
    println(&quot;C'est bon, entrez !&quot;)
    true
}</pre></td></tr></table></pre>
</div>Il va de soi que les différentes branches doivent retourner des valeurs compatibles.<br />
<br />
Une autre situation : le mot-clé when :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">
val resultat = java.util.Random().nextInt(21)
	println(when (resultat) {
       in 0..9 -&gt; &quot;Passable&quot;
       in 10..14 -&gt; &quot;Bien&quot;
       in 15..18 -&gt; &quot;Très bien&quot;
       in 18..20 -&gt; &quot;Excellent et prometteur !&quot;
       else -&gt; throw IllegalArgumentException()
    })</pre></td></tr></table></pre>
</div>Alors plusieurs remarques sur le code :<br />
<ul><li style="">j'utilise directement le résultat de l'expression offerte par when dans la fonction println</li><li style="">je teste à chaque fois si la valeur figure dans la plage donnée. En effet le mot-clé in permet de tester l'appartenance (de manière générale sur tout itérateur) et 0..9 est une &quot;range&quot;, un intervalle valant [0,9] pour les matheux. Pour les autres cela signifie simplement que les valeurs 0 et 9 sont comprises. Enfin, les range en Kotlin n'impliquent que des entiers</li><li style="">j'utilise une forme générique de when : on peut tester de simples valeurs, des intervalles, le fait que ce soit une instance de telle classe ... Plus d'exemples dessous.</li><li style="">enfin, si je lance une exception, son type de retour est Nothing, et comme Nothing est considéré comme sous-classe de toutes les classes existantes en Kotlin, cela ne pose aucun problème. Alors que vaut Nothing ? Et bien rien ! En effet, quand je lance une exception le programme s'arrête ou en tout cas la fonction où elle est lancée si il n'y a pas de try/catch</li></ul><br />
<br />
Avant de finir avec l'utilisations de when, il faut être conscient que try/catch/finally est aussi une expression !<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:132px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td valign="top"><pre style="margin: 0">
val nombre = try {
  10 / 0
} catch (e: ArithmeticException){
   0
}

println(&quot;Nombre vaut $nombre&quot;)</pre></td></tr></table></pre>
</div>Comme vous l'aurez probablement deviné sans même passer par le playground Kotlin, ce code affiche tout simplement &quot;Nombre vaut 0&quot;.<br />
<br />
Revenons maintenant, sur le mot-clé when.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:120px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td valign="top"><pre style="margin: 0">
    val a = 10
    when {
       a in -10..3 -&gt; println(&quot;Evidement ça ne passe pas ici !&quot;)
       a &lt; -1 -&gt; println(&quot;Là non plus !&quot;)
       else -&gt; println(&quot;C'est bon !&quot;)
    }</pre></td></tr></table></pre>
</div>Ceci est la forme générique du when, sans test de variable direct. Notez bien qu'afin de couvrir tous les cas imaginables, le mot-clé else est ici obligatoire (c'est le default du switch de java). Aussi, on ne peut comparer un Int et un Double en Kotlin (si j'avais précisé `a !is Double` dans l'une des branches, j'aurais eu une erreur de syntaxe). Le trantypage automatique n'existe pas en Kotlin (un choix qui peut paraître honorable).<br />
<br />
Cette forme <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
     val a = 10
    println(when (a) {
        in -10..-1, in 1..10 -&gt; &quot;Valeur non nulle&quot;
        else -&gt; &quot;Valeur nulle&quot;
    })</pre></td></tr></table></pre>
</div>est la forme directe que nous avons déjà rencontré auparavant.<br />
<br />
Voilà, j'espère que vous aurez pris du plaisir à lire ce billet :)</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3667/kotlin-expressions/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Nullabilité ?]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3659/kotlin-nullabilite/</link>
			<pubDate>Thu, 31 Aug 2017 06:57:29 GMT</pubDate>
			<description>Amis programmeurs Kotlin,...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Amis programmeurs Kotlin, pour ceux qui auraient remarqué, désolé pour l'humour bidon :mrgreen:<br />
Les autres auront la possibilité de comprendre après avoir lu ce billet :)<br />
<br />
<u>Qu'est-ce qui différencie un type &quot;nullable&quot; d'un type standard ?</u><br />
<br />
En java toute référence (donc non sur un type primitif) peut pointer<br />
<ul><li style="">soit sur un objet défini</li><li style="">soit sur la valeur null</li></ul><br />
A ce propos : en Kotlin, il n'y a pas la notion de type primitif et de wrapper. Par défaut, un Int est converti vers une type primitif pour des raisons de performances, et sinon dans un type java.lang.Integer quand cela n'est pas possible pour le compilateur.<br />
<br />
Cependant en Kotlin, une distinction très importante et utile est faite par le compilateur entre un type qui peut valoir null, et <b><u><i>un type qui n'acceptera jamais la valeur null</i></u></b>.<br />
Illustration avec le snippet suivant :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
val age:Int = 10 // ok
val age:Int = null // erreur de compilation !!!

(A) val adresse:String? = &quot;Saint-Germain en Laye&quot; // Besoin de commenter ?
(B) val adresse:String? = null // Ok, ca passe sans problème</pre></td></tr></table></pre>
</div>Ainsi un type nullable se déclare avec le type de base auquel on ajoute le symbole '?'.<br />
<br />
Alors, que se passe-t-il si je veux accéder à la longueur de la chaîne adresse ci-dessus ? Et bien, surprise (ou non), mais dans l'extrait (A) tout comme l'extrait (B), il y aura une erreur de compilation ! Avouez que cela est bien utile pour éviter bien des écueils :)<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val adresse:String? = &quot;Saint-Germain en Laye&quot; 
println(adresse.length) // erreur de compilation !!! Impossible d'accéder à la propriété length car adresse est nullable !</pre></td></tr></table></pre>
</div>Mais alors, comment malgré tout accéder à la longueur &quot;au moins&quot; -vous comprendrez plus tard dans ce billet&quot; - dans le cas (A) , où l'on sait pourtant plus que le compilateur et on est sûr que la valeur n'est pas null ?<br />
C'est justement l'objectif de la section suivante, mais juste à titre d'exemple, on pourrait écrire<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val adresse:String? = &quot;Saint-Germain en Laye&quot; 
if (adresse != null) println(adresse.length)</pre></td></tr></table></pre>
</div><u>L'utilisation d'un type nullable</u><br />
<br />
Comme nous l'avons vu plus haut, la structure de contrôle if permet d'utiliser simplement une valeur nullable :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val adresse:String? = &quot;Saint-Germain en Laye&quot; 
if (adresse != null) println(adresse.length)</pre></td></tr></table></pre>
</div>Question d'observation : avez-vous remarqué l'utilisation de la variable adresse sans avoir effectué aucun casting de String? vers String ? Ici on a une nouvelle application de la notion de <b><u><i>Smart-Cast</i></u></b>, tel que décrit dans un précédent billet.<br />
<br />
Toutefois cela ne peut fonctionner avec le mot-clé when : cette structure de contrôle n'acceptant que des comparaison de valeurs (sans &quot;is&quot;) ou de type (avec &quot;is&quot;, comme vu précédemment dans la section casting de types) : à moins de s'embêter à vérifier les deux types, à savoir nullable et non nullable. Mais quel en serait l'intérêt :weird: ?<br />
<br />
Sinon il y a un moyen beacoup plus simple de s'y prendre, qui combine deux syntaxes n'existant pas en Java :<br />
<ul><li style="">l'acces à une propriété nullable (.?)</li><li style="">l'opérateur Elvis (?:)</li></ul><br />
<br />
Avec l'accès à une propriété nullable :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
val monNullable: String? = &quot;12345&quot;
val monNull: String? = null

println(monNullable?.length) // affiche 5
println(monNull?.length) // n'affiche rien !!!</pre></td></tr></table></pre>
</div>Ainsi, pour la variable monNull, monNull?.length retourne null, sans provoquer d'exception, et l'instruction associée (à savoir println) n'est pas exécutée.<br />
<br />
On aurait pu aussi afficher une valeur par défaut, une valeur de substitution pour ce cas précis. En effet, Kotlin reconnaît l'opérateur elvis (?:) :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
val monNullable: String? = &quot;12345&quot;
val monNull: String? = null

println(monNullable?.length ?: 0) // affiche 5
println(monNull?.length ?: 0) // affiche 0</pre></td></tr></table></pre>
</div>Voilà, j'espère que vous aurez pris plaisir à lire ce billet :)</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3659/kotlin-nullabilite/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Documentation officielle et livre recommandé]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3654/kotlin-documentation-officielle-livre-recommande/</link>
			<pubDate>Thu, 31 Aug 2017 04:53:30 GMT</pubDate>
			<description>Amis programmeurs de Kotlin,...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Amis programmeurs de Kotlin, voici quelques ressources intéressantes :<br />
<br />
<ul><li style=""><a href="http://kotlinlang.org/docs/reference/" target="_blank">Documentation et page officielle de Kotlin</a> : Pourquoi ne pas commencer par la page <a href="http://kotlinlang.org/docs/reference/idioms.html" target="_blank">Idioms</a>, qui vous donne un bref tour du langage ?</li><li style=""><a href="https://www.manning.com/books/kotlin-in-action" target="_blank">Kotlin in Action</a></li><li style=""><a href="https://www.editions-eni.fr/livre/kotlin-les-fondamentaux-du-developpement-d-applications-android-9782409015861" target="_blank">Les fondamentaux du développement d'applications Android (Edition ENI)</a></li></ul></blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3654/kotlin-documentation-officielle-livre-recommande/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Essayer son propre code en ligne (et donc les snippets de ce tutoriel)]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3649/kotlin-essayer-propre-code-ligne-snippets-tutoriel/</link>
			<pubDate>Thu, 31 Aug 2017 04:48:35 GMT</pubDate>
			<description>Voici une adresse très utile,...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Voici une adresse très utile, amis programmeurs Kotlin : <a href="https://try.kotlinlang.org/#/Kotlin%20Koans/Generics/Generic%20functions/Task.kt" target="_blank">Playground Kotlin</a>.<br />
N'hésitez pas à tester<br />
<ul><li style="">vos propres codes</li><li style="">les snippets du tutoriel (attention toutefois à les insérer dans la méthode main quand les snippets ne le font pas !)</li><li style="">les koans et autres snippets, certes en anglais, offerts par JetBrains</li></ul><br />
<br />
Au cas où vous aurez tout effacé, la méthode main, en Kotlin, se déclare ainsi :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
fun main(args: Array&lt;String&gt;){
}</pre></td></tr></table></pre>
</div>Allez, amusez-vous bien :)</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3649/kotlin-essayer-propre-code-ligne-snippets-tutoriel/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Casting par le biais du mot-clé "when"]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3645/kotlin-casting-biais-cle-when/</link>
			<pubDate>Wed, 30 Aug 2017 09:11:51 GMT</pubDate>
			<description>Contrairement au Java, bien...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Contrairement au Java, bien qu'il existe un mot-clé dédié à cet effet, le casting de type se fait à l'aide d'une structure de contrôle. Elle s'appelle <u>when</u> : c'est en quelque sorte la structure <u>switch</u> de Java mais bien plus puissante. Par contre ici, nous nous limiterons à l'une des utilisations les plus simple afin de pouvoir effectuer un casting de type.<br />
<br />
Soit la hiérarchie de classes suivantes (vous noterez que créer une classe en Kotlin est bien plus simple qu'en Java) :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:156px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td valign="top"><pre style="margin: 0">
class Figure
class Rectangle(val largeur: Double val longueur: Double) : Figure {
    fun perimetre(): Double = 2*(largeur + longueur)
}
class Cercle(val centre: Point, val rayon: Double) : Figure {
   fun aire() : Double {
       return 2*Math.PI*rayon
   }
}</pre></td></tr></table></pre>
</div>Ici je déclare une classe <b>concrète</b> Figure qui ne fait absolument rien.<br />
Quatre remarques importantes :<br />
<ul><li style="">On déclare le constructeur en même temps que la classe. (Comment alors définir plusieurs constructeurs ? Cela sera l'objet d'un billet ultérieur:P),</li><li style="">Pour dériver une classe, on utilise la syntaxe &quot;: &lt;Classe de Base&gt;&quot;, avec éventuellement les paramètres renseignés pour le constructeur de la classe de base (Idem pour le cas des constructeurs multiples pour la classe de base : ce sera l'objet d'un billet ultérieur),</li><li style="">On déclare le type d'une variable avec la syntaxe &quot;val &lt;NomVariable&gt; : &lt;Type&gt;&quot; , comme vu dans le billet précédent sur l'immutabilité,</li><li style="">Enfin le fait de déclarer un paramètre comme <b>val</b> permet de créer automatiquement un getter (et aucun setter) pour la variable déclarée tandis que l'utilisation de <b>var</b> permet de générer automatiquement à la fois un getter et un setter pour la dite propriété.</li></ul><br />
<br />
Je vous prie de ne pas attacher trop d'importante à la syntaxe de déclaration de fonctions/méthodes (notamment aire() et perimetre()) pour l'instant.<br />
<br />
Ainsi, le code suivant est valide :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:168px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td valign="top"><pre style="margin: 0">
class Adress(val ville: String, val codePostal: Int)
class Person(val nom: String, val prenom: String, var adress: Adress)

val noemie = Person(&quot;Tartempion&quot;, &quot;Noemie&quot;, Adress(&quot;Troyes&quot;, 10420))
println(noemie.adress.ville) // afficher du texte sur la sortie standard est bien plus simple en Kotlin.
noemie.adress = (&quot;Strasbourg&quot;, 67000)
// En revanche le code suivant provoquera une erreur de compilation
noemie.prenom = &quot;Toto&quot;
//De même celui-là
noemie.adress.codePostal = 15200</pre></td></tr></table></pre>
</div>Remarquez aussi que l'on crée une instance de classe sans le mot-clé <b>new</b>, contrairement au Java.<br />
<br />
Il me manque aussi la classe Point :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">
class Point(val x: Double, val y: Double)</pre></td></tr></table></pre>
</div>Nous pouvons donc écrire le code suivant :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:156px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td valign="top"><pre style="margin: 0">
val allFigures = arrayOf(Rectangle(10.0, 20.0), Cercle(Point(5.0, -15.0), 20.0) // Déclare un simple tableau de Figures (polymorphique)
// Ecriture equivalente : val allFigures = arrayOf&lt;Figures&gt;(Rectangle(10.0, 20.0), Cercle(Point(5.0, -15.0), 20.0) : le precent code fait appel à l'inference de type

for (currentFigure in allFigures) {
   when (currentFigure) {
       is Rectangle -&gt; println(&quot;Mon permimetre est de ${currentFigure.perimetre()}&quot;)
       is Cercle -&gt; println(&quot;Mon aire est de ${currentFigure.aire()}&quot;)
   }
}</pre></td></tr></table></pre>
</div>Plusieurs remarques sur le code précédent :<br />
<ul><li style="">La boucle for est simplifiée par rapport au Java : écrire &quot;for (valeur: Int = 0; valeur &lt; 10; valeur++)&quot; ou tout code de ce genre est totalement interdit en Kotlin. Il faut obligatoirement passer par un itérateur !</li><li style="">On teste dans chaque branche de <b>when</b> à l'aide du mot clé <b>if</b>, et on ne met ni point-virgule, ni virgule ... rien en fin de ligne de chaque branche !!!</li><li style="">Ici je crée une <b><u>TemplateString </u></b>: dès que le compilateur verra $a dans la chaîne &quot;Voici a : $a&quot;, il remplacera la chaîne &quot;$a&quot; par la valeur de a. Par contre si l'on doit utiliser une expression, il faut l'englober dans des accolades, comme dans le code.</li><li style="">Enfin, l'aspect le plus inattendu, le <b><u><i>SmartCast</i></u></b>. Une fois que le compilateur voit <i>is Rectangle</i>, c'est comme si il avait aussitôt transformé lui-même la variable currentFigure en instance de Rectangle, de sorte que la méthode perimetre() peut être directement appellée. Mais attention, cela ne vaut que pour cette branche-ci ! De même pour la branche is Cercle.</li></ul><br />
<br />
Voilà ! En espérant ne pas trop vous avoir noyé et que vous avez pris du plaisir à lire ce billet !</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3645/kotlin-casting-biais-cle-when/</guid>
		</item>
		<item>
			<title><![CDATA[[Kotlin] Immutabilité]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3643/kotlin-immutabilite/</link>
			<pubDate>Wed, 30 Aug 2017 08:29:19 GMT</pubDate>
			<description>En programmant sous Kotlin,...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">En programmant sous Kotlin, la gestion de l'immutabilité est ultra-simple. Par exemple dans le code suivant :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val a = 10
val b = &quot;Toto&quot;</pre></td></tr></table></pre>
</div>Les variables a et b valent respectivement 10 et &quot;Toto&quot; et ce, <b>de manière définitive</b> !<br />
<br />
Remarquez d'ailleurs que j'ai ici utilisé <u>l'inférence de type,</u> qui consiste à laisser le compilateur deviner le type de variable lui-même.<br />
J'aurais très bien pu écrire :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">
val a:Int = 10
val b:String = &quot;Toto&quot;</pre></td></tr></table></pre>
</div>Où ici Int représente soit un entier primitif ou un wrapper Int (en l’occurrence ici un entier primitif car on a déclaré un littéral : 10).<br />
<br />
Veuillez remarquer l'absence de point-virgules en fin de ligne : ils sont optionnels.<br />
<br />
Enfin, pour déclarer une variable que l'on sait muable, il faut utiliser le mot-clé <b><u>var</u></b> en lieu et place de <b><u>val</u></b>.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
var a = 10
var b = &quot;Toto&quot;

a = 120
b = &quot;Gros zéro !&quot;</pre></td></tr></table></pre>
</div>Voilà, en espérant que vous aurez pris plaisir à lire (voir relire) ce billet !</blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3643/kotlin-immutabilite/</guid>
		</item>
		<item>
			<title><![CDATA[[C++11]Constructeur par copie et opérateurs d'affectations : comment éviter de dupliquer le code ?]]></title>
			<link>https://www.developpez.net/forums/blogs/26529-tails/b3271/cpp11-constructeur-copie-operateurs-d-affectations-eviter-dupliquer-code/</link>
			<pubDate>Thu, 22 Jun 2017 12:03:11 GMT</pubDate>
			<description>Récemment je me suis demandé...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Récemment je me suis demandé comment initialiser proprement une classe avec les différents constructeurs et opérateurs de copie/affection proprement, sans dupliquer le code, étant donné que la classe ne compte aucun pointeur nu. Je me suis donc orienté sur le forum de developpez. La réponse citée vient du topic que j'ai crée à ce sujet.<br />
<br />
Et je dois dire que j'ai appris pas mal de choses durant cette discussion, dont notamment :<br />
<ul><li style="">l'utilisation de std::move (header &lt;utility&gt;) pour gérer proprement le transfert</li><li style="">le 4e constructeur (dont j'ignorais complètement l'existence)</li></ul><br />
<br />
Bref, cela a été pour moi une excellente occasion de renforcer mes connaissances et mes bonnes pratiques.<br />
<br />
<a href="https://www.developpez.net/forums/d1714585/c-cpp/cpp/langage/constructeur-copie-operateurs-d-affectations-eviter-dupliquer-code/#post9392999" target="_blank">Page de la discussion originale</a><br />
<br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>tails</strong>
					<a href="showthread.php?p=9389700#post9389700" rel="nofollow"><img class="inlineimg" src="https://forum.developpez.be/images/buttons/viewpost-right.png" alt="Voir le message" /></a>
				</div>
				<div class="message">Bonjour à tous :)<br />
<br />
J'ai besoin de créer un constructeur par copie dans une classe personnelle, et deux opérateurs d'affectations (un avec une R-Value), mais j'ai dû dupliquer le code :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td valign="top"><pre style="margin: 0">
Operation::Operation(const Operation &amp;valueToCopy){
    this-&gt;_operator = valueToCopy._operator;
    this-&gt;_tile_1 = valueToCopy._tile_1;
    this-&gt;_tile_2 = valueToCopy._tile_2;
}

Operation&amp; Operation::operator=(Operation&amp;&amp; valueToCopy){
    this-&gt;_operator = valueToCopy._operator;
    this-&gt;_tile_1 = valueToCopy._tile_1;
    this-&gt;_tile_2 = valueToCopy._tile_2;
    return *this;
}

Operation&amp; Operation::operator=(const Operation&amp; valueToCopy){
    this-&gt;_operator = valueToCopy._operator;
    this-&gt;_tile_1 = valueToCopy._tile_1;
    this-&gt;_tile_2 = valueToCopy._tile_2;
    return *this;
}</pre></td></tr></table></pre>
</div>(Si vous vous demandez pourquoi les 3, c'est simplement pour mieux utiliser la STL, elles paraissent indispensables pour utiliser les méthodes de certaines collections).<br />
<br />
Comment faire plus simple, factoriser tout cela en réutilisant l'une des 3 méthodes dans les deux autres ? J'avais vu dans un cours, mais j'ai carrément oublié.<br />
<br />
Autre question liée : vu que je n'utilise pas de pointeur nu dans ma classe, je n'ai pas besoin de surcharger le destructeur : n'est-ce pas ?</div>
			
		</div>
	</div>
</div><div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>dalfab</strong>
					<a href="showthread.php?p=9391184#post9391184" rel="nofollow"><img class="inlineimg" src="https://forum.developpez.be/images/buttons/viewpost-right.png" alt="Voir le message" /></a>
				</div>
				<div class="message">Je ne vois pas du tout l’intérêt de ces fonctions qui ne font que ce que font les fonctions par défaut. Mais en nettement moins optimal!<br />
Voilà le code qui est utilisé si ces fonctions ne sont jamais déclarés ou si elles sont définies en &quot;= default&quot; :<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td valign="top"><pre style="margin: 0">Operation::Operation( const Operation &amp;valueToCopy )
:  _operator(valueToCopy._operator),
   _tile_1(valueToCopy._tile_1) ,  _tile_2(valueToCopy._tile_2) {
       // crée les 3 membres et les initialise en même temps
}

Operation&amp; Operation::operator=( Operation&amp;&amp; valueToCopy ) {
   this-&gt;_operator = std::move(valueToCopy._operator);
   this-&gt;_tile_1 = std::move(valueToCopy._tile_1);
   this-&gt;_tile_2 = std::move(valueToCopy._tile_2);
   // fait un transfert des éléments au lieu d'une simple copie
   return *this;
}
 
Operation&amp; Operation::operator=( const Operation &amp;valueToCopy ) {
    // peut utiliser un swap par exemple ou
   if ( &amp;valueToCopy != this ) {
      this-&gt;_operator = valueToCopy._operator;
      this-&gt;_tile_1 = valueToCopy._tile_1;
      this-&gt;_tile_2 = valueToCopy._tile_2;
   }
   return *this;
}

// et il manque une quatrième, le constructeur par transfert
Operation::Operation( Operation&amp;&amp; valueToMove )
:  _operator(std::move(valueToMove._operator)),
   _tile_1(std::move(valueToMove._tile_1)) ,  _tile_2(std::move(valueToMove._tile_2) {
}</pre></td></tr></table></pre>
</div></div>
			
		</div>
	</div>
</div></blockquote>

]]></content:encoded>
			<dc:creator>tails</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/26529-tails/b3271/cpp11-constructeur-copie-operateurs-d-affectations-eviter-dupliquer-code/</guid>
		</item>
	</channel>
</rss>
