En C / C ++ (et dans de nombreux langages de cette famille), un idiome commun pour déclarer et initialiser une variable en fonction d'une condition utilise l'opérateur conditionnel ternaire:
int index = val > 0 ? val : -val
Go n'a pas l'opérateur conditionnel. Quelle est la façon la plus idiomatique d'implémenter le même morceau de code que ci-dessus? Je suis arrivé à la solution suivante, mais elle semble assez verbeuse
var index int
if val > 0 {
index = val
} else {
index = -val
}
Y a-t-il quelque chose de mieux?
int index = -val + 2 * val * (val > 0);
Réponses:
Comme souligné (et sans surprise, espérons-le), l'utilisation
if+else
est en effet la façon idiomatique de faire des conditions dans Go.En plus du
var+if+else
bloc de code complet , cette orthographe est également souvent utilisée:et si vous avez un bloc de code suffisamment répétitif, comme l'équivalent de
int value = a <= b ? a : b
, vous pouvez créer une fonction pour le contenir:Le compilateur insérera ces fonctions simples, il est donc rapide, plus clair et plus court.
la source
c := (map[bool]int{true: a, false: a - 1})[a > b]
est un exemple d'obscurcissement à mon humble avis, même si cela fonctionne.if/else
est l'approche idiomatiques alors peut - être golang pourrait envisager de laisser desif/else
clauses retourner une valeur:x = if a {1} else {0}
. Go ne serait en aucun cas la seule langue à fonctionner de cette façon. Un exemple courant est Scala. Voir: alvinalexander.com/scala/scala-ternary-operator-syntaxNo Go n'a pas d'opérateur ternaire, en utilisant la syntaxe if / else est la manière idiomatique.
la source
if-else
bloc entier ? Et qui a ditif-else
ne pas être abusé de la même manière? Je ne t'attaque pas, j'ai juste l'impression que l'excuse des designers n'est pas assez valableSupposons que vous ayez l'expression ternaire suivante (en C):
L'approche idiomatique dans Go serait d'utiliser simplement un
if
bloc:Cependant, cela pourrait ne pas correspondre à vos besoins. Dans mon cas, j'avais besoin d'une expression en ligne pour un modèle de génération de code.
J'ai utilisé une fonction anonyme immédiatement évaluée:
Cela garantit que les deux branches ne sont pas également évaluées.
la source
expr1 ? expr2 : expr3
. Siexpr1
évalue àtrue
,expr2
est évalué et est le résultat de l'expression. Sinon,expr3
est évalué et fourni comme résultat. Ceci provient de la section 2.11 du langage de programmation C ANSI de K&R. Ma solution Go conserve ces sémantiques spécifiques. @Wolf Pouvez-vous clarifier ce que vous proposez?La carte ternaire est facile à lire sans parenthèses:
la source
simple and clear code is better than creative code.
Cela ne surclassera pas si / else et nécessite un cast mais fonctionne. Pour info:
BenchmarkAbsTernary-8 100000000 18.8 ns / op
BenchmarkAbsIfElse-8 2000000000 0,27 ns / op
la source
Si toutes vos branches produisent des effets secondaires ou sont coûteuses en calcul, ce qui suit serait une refactorisation sémantiquement préservée :
sans surcharge (en ligne) et, surtout, sans encombrer votre espace de noms avec des fonctions d'assistance qui ne sont utilisées qu'une seule fois (ce qui nuit à la lisibilité et à la maintenance). Exemple en direct
Notez si vous deviez appliquer naïvement l'approche de Gustavo :
vous obtiendriez un programme avec un comportement différent ; au cas où le
val <= 0
programme imprimerait une valeur non positive alors qu'il ne devrait pas! (De façon analogue, si vous inversiez les branches, vous introduiriez une surcharge en appelant une fonction lente inutilement.)la source
abs
fonction dans le code original (bien, je changerais<=
à<
). Dans votre exemple, je vois une initialisation, qui est redondante dans certains cas et pourrait être expansive. Pouvez-vous préciser: expliquez un peu plus votre idée?printPositiveAndReturn
n'est appelée que pour les nombres positifs. Inversement, toujours exécuter une branche, puis "fixer" la valeur avec l'exécution d'une branche différente n'annule pas les effets secondaires de la première branche .Avant-propos: Sans prétendre que
if else
c'est la voie à suivre, nous pouvons toujours jouer avec et trouver du plaisir dans les constructions basées sur le langage.La
If
construction suivante est disponible dans magithub.com/icza/gox
bibliothèque avec beaucoup d'autres méthodes, étant lebuiltinx.If
type.Go permet d'attacher des méthodes à tous les types définis par l'utilisateur , y compris les types primitifs tels que
bool
. Nous pouvons créer un type personnalisé ayantbool
comme type sous-jacent , puis avec une conversion de type simple à la condition, nous avons accès à ses méthodes. Méthodes qui reçoivent et sélectionnent les opérandes.Quelque chose comme ça:
Comment pouvons-nous l'utiliser?
Par exemple un ternaire faisant
max()
:Un ternaire faisant
abs()
:Cela a l'air cool, c'est simple, élégant et efficace (il est également éligible pour l'inline ).
Un inconvénient par rapport à un "vrai" opérateur ternaire: il évalue toujours tous les opérandes.
Pour obtenir une évaluation différée et uniquement si nécessaire, la seule option consiste à utiliser des fonctions (soit des fonctions ou méthodes déclarées , soit des littéraux de fonction ), qui ne sont appelées que lorsque / si nécessaire:
Utilisation: Supposons que nous avons ces fonctions pour calculer
a
etb
:Ensuite:
Par exemple, la condition étant l'année en cours> 2020:
Si nous voulons utiliser des littéraux de fonction:
Remarque finale: si vous aviez des fonctions avec des signatures différentes, vous ne pourriez pas les utiliser ici. Dans ce cas, vous pouvez utiliser un littéral de fonction avec une signature correspondante pour les rendre toujours applicables.
Par exemple, si
calca()
etcalcb()
aurait également des paramètres (en plus de la valeur de retour):Voici comment vous pouvez les utiliser:
Essayez ces exemples sur le Go Playground .
la source
La réponse d'Eold est intéressante et créative, peut-être même intelligente.
Cependant, il serait recommandé de faire à la place:
Oui, ils se compilent tous les deux essentiellement vers le même assembly, mais ce code est beaucoup plus lisible que d'appeler une fonction anonyme juste pour renvoyer une valeur qui aurait pu être écrite dans la variable en premier lieu.
Fondamentalement, un code simple et clair est meilleur qu'un code créatif.
De plus, tout code utilisant un littéral de carte n'est pas une bonne idée, car les cartes ne sont pas du tout légères dans Go. Depuis Go 1.3, l'ordre d'itération aléatoire pour les petites cartes est garanti, et pour l'appliquer, il est devenu un peu moins efficace en termes de mémoire pour les petites cartes.
Par conséquent, la création et la suppression de nombreuses petites cartes prennent à la fois de l'espace et du temps. J'avais un morceau de code qui utilisait une petite carte (deux ou trois clés, probablement, mais le cas d'utilisation courant n'était qu'une entrée) Mais le code était lent. Nous parlons d'au moins 3 ordres de grandeur plus lentement que le même code réécrit pour utiliser une clé à double tranche [index] => data [index] map. Et c'était probablement plus. Comme certaines opérations qui prenaient auparavant quelques minutes à exécuter, ont commencé à se terminer en millisecondes. \
la source
simple and clear code is better than creative code
- ça j'aime beaucoup, mais je suis un peu confus dans la dernière section aprèsdog slow
, peut-être que ça pourrait être déroutant pour les autres aussi?m := map[string]interface{} { a: 42, b: "stuff" }
, puis dans une autre fonction, itérant à travers celui-ci:for key, val := range m { code here }
Après être passé à un système à deux trancheskeys = []string{ "a", "b" }, data = []interface{}{ 42, "stuff" }
:, puis parcourez comme desfor i, key := range keys { val := data[i] ; code here }
choses accélérées 1000 fois.Les doublures, bien que rejetées par les créateurs, ont leur place.
Celui-ci résout le problème de l'évaluation paresseuse en vous laissant, éventuellement, passer des fonctions à évaluer si nécessaire:
Production
interface{}
pour satisfaire l'opération de transtypage interne.c
.La solution autonome ici est également agréable, mais pourrait être moins claire pour certaines utilisations.
la source