В C / C ++ (и многих языках этого семейства) общая идиома объявления и инициализации переменной в зависимости от условия использует троичный условный оператор:
int index = val > 0 ? val : -val
Go не имеет условного оператора. Какой самый идиоматичный способ реализовать тот же кусок кода, что и выше? Я пришел к следующему решению, но оно кажется довольно многословным
var index int
if val > 0 {
index = val
} else {
index = -val
}
Есть ли что-то лучше?
int index = -val + 2 * val * (val > 0);
Ответы:
Как указывалось (и, надеюсь, неудивительно), использование
if+else
действительно является идиоматическим способом выполнения условных выражений в Go.В дополнение к полноценному
var+if+else
блоку кода, это написание также часто используется:и если у вас есть достаточно повторяющийся блок кода, например, эквивалент
int value = a <= b ? a : b
, вы можете создать функцию для его хранения:Компилятор встроит такие простые функции, поэтому он быстрее, понятнее и короче.
источник
c := (map[bool]int{true: a, false: a - 1})[a > b]
это пример запутывания ИМХО, даже если оно работает.if/else
это идиоматическое подход , то , возможно , мог бы рассмотреть Golang позволитьif/else
пункты возврата значения:x = if a {1} else {0}
. Go не будет единственным языком, который будет работать таким образом. Основным примером является Scala. См .: alvinalexander.com/scala/scala-ternary-operator-syntaxNo Go не имеет троичного оператора, использование синтаксиса if / else является идиоматическим способом.
источник
if-else
блока? И кто говорит, чтоif-else
не злоупотребляет подобным образом? Я не нападаю на вас, я просто чувствую, что оправдание дизайнеров недостаточно обоснованноПредположим, у вас есть следующее троичное выражение (в C):
Идиоматический подход в Go будет просто использовать
if
блок:Однако это может не соответствовать вашим требованиям. В моем случае мне нужно было встроенное выражение для шаблона генерации кода.
Я использовал немедленно оцененную анонимную функцию:
Это гарантирует, что обе ветви также не оцениваются.
источник
expr1 ? expr2 : expr3
. Если имеетexpr1
значениеtrue
,expr2
оценивается и является результатом выражения. В противном случаеexpr3
оценивается и предоставляется как результат. Это из раздела 2.11 языка программирования ANSI C от K & R. Решение My Go сохраняет эту специфическую семантику. @ Волк Можете ли вы уточнить, что вы предлагаете?Карта троичного легко читается без скобок:
источник
simple and clear code is better than creative code.
Это не будет превосходить, если / иначе и требует приведение, но работает. FYI:
BenchmarkAbsTernary-8 100000000 18,8 нс / оп
BenchmarkAbsIfElse-8 2000000000 0,27 нс / оп
источник
Если все ваши ветки имеют побочные эффекты или требуют больших вычислительных ресурсов , то семантически сохраняющий рефакторинг приведёт к следующему :
обычно без накладных расходов (встроенные) и, что наиболее важно, без загромождения пространства имен вспомогательными функциями, которые используются только один раз (что затрудняет читаемость и обслуживание). Живой пример
Обратите внимание, если вы должны были наивно применять подход Густаво :
вы получите программу с другим поведением ; в случае если
val <= 0
программа выдаст неположительное значение, а это не так! (Аналогично, если бы вы изменили направление ветвлений, вы бы добавили накладные расходы, без необходимости вызывая медленную функцию.)источник
abs
функцию в исходном коде (ну, я бы изменил<=
на<
). В вашем примере я вижу инициализацию, которая в некоторых случаях является избыточной и может быть обширной. Не могли бы вы уточнить: объясните свою идею немного подробнее?printPositiveAndReturn
вызывается только для положительных чисел. И наоборот, всегда выполняя одну ветвь, тогда «исправление» значения при выполнении другой ветки не отменяет побочных эффектов первой ветви .Предисловие: не споря, что
if else
это путь, мы все еще можем играть и получать удовольствие от конструкций с поддержкой языка.Следующая
If
конструкция доступна в моейgithub.com/icza/gox
библиотеке с множеством других методов, являющихсяbuiltinx.If
типом.Go позволяет прикреплять методы к любым пользовательским типам , включая такие примитивные, как
bool
. Мы можем создать пользовательский тип , имеющий вbool
качестве базового типа , а затем с помощью простого типа преобразования при условии, мы имеем доступ к его методам. Методы, которые получают и выбирают из операндов.Что-то вроде этого:
Как мы можем использовать это?
Например троичный делает
max()
:Троицы делают
abs()
:Это выглядит круто, это просто, изящно, и эффективно (это также имеет право на встраивание ).
Один недостаток по сравнению с «настоящим» троичным оператором: он всегда оценивает все операнды.
Для достижения отложенной и только в случае необходимости оценки, единственный вариант - использовать функции (либо объявленные функции или методы, либо литералы функций ), которые вызываются только когда / при необходимости:
Используя его: давайте предположим, что у нас есть эти функции для вычисления
a
иb
:Затем:
Например, текущее состояние> 2020:
Если мы хотим использовать функциональные литералы:
Последнее замечание: если у вас будут функции с разными сигнатурами, вы не сможете использовать их здесь. В этом случае вы можете использовать функциональный литерал с соответствующей сигнатурой, чтобы сделать их все еще применимыми.
Например, если
calca()
иcalcb()
будет иметь параметры (кроме возвращаемого значения):Вот как вы можете их использовать:
Попробуйте эти примеры на игровой площадке Go .
источник
Ответ Эольда интересный и креативный, возможно, даже умный.
Тем не менее, рекомендуется вместо этого сделать:
Да, они оба компилируются по существу в одну и ту же сборку, однако этот код гораздо более разборчив, чем вызов анонимной функции только для того, чтобы вернуть значение, которое могло быть записано в переменную в первую очередь.
По сути, простой и понятный код лучше творческого кода.
Кроме того, любой код, использующий литерал карты, не является хорошей идеей, поскольку карты на Go совсем не легки. Начиная с Go 1.3, случайный порядок итераций для маленьких карт гарантирован, и для обеспечения этого он стал немного менее эффективным с точки зрения памяти для маленьких карт.
В результате создание и удаление многочисленных небольших карт занимает много места и времени. У меня был кусок кода, в котором использовалась небольшая карта (скорее всего, два или три ключа, но в общем случае использовалась только одна запись) Но код был слишком медленным. Мы говорим как минимум на 3 порядка медленнее, чем тот же код, переписанный для использования карты двойного ключа [index] => data [index]. И скорее всего было больше. Поскольку некоторые операции, которые раньше выполнялись за пару минут, начали выполняться за миллисекунды. \
источник
simple and clear code is better than creative code
- это мне очень нравится, но я немного запутался в последнем разделе послеdog slow
, может быть, это может сбить с толку и других?m := map[string]interface{} { a: 42, b: "stuff" }
, а затем и другая функция, перебирающая ее:for key, val := range m { code here }
после переключения на двухслойную систему:,keys = []string{ "a", "b" }, data = []interface{}{ 42, "stuff" }
а затем перебираем, какfor i, key := range keys { val := data[i] ; code here }
вещи ускоряются в 1000 раз.Однострочники, хотя создатели избегают их, имеют свое место.
Это решает проблему отложенной оценки, позволяя вам, при необходимости, передавать функции для оценки при необходимости:
Вывод
interface{}
для удовлетворения внутренней операции приведения.c
.Автономное решение здесь также хорошо, но может быть менее понятным для некоторых применений.
источник