Тернарный оператор как слева, так и справа.. или ни
ВОПРОС: Если вам понятна эта проблема, пожалуйста, объясните мне, что я не вижу. Мой вопрос: как троичный на самом деле работает? Чтобы прояснить мой вопрос: что на самом деле означает ассоциативность справа налево? Почему ассоциативность не совпадает с порядком оценки? Это явно похоже на утверждение if else. Он не оценивается справа налево. Мне кажется, что слева направо ассоциативно.
Я сделал логическое выражение, чтобы попытаться доказать это. Это показывает мне, что это не правая ассоциация. (Я не могу понять, что означает правильная ассоциация.) Если бы это была правильная ассоциация, она бы работала так, что мне ответили:
"Поскольку этот оператор является ассоциативным справа, ваш код работает как;"
true ? false ? false ? false ? 3 : 4 : 5 : 6 : 7
evaluated as;
true ? false ? false ? (false ? 3 : 4) : 5 : 6 : 7
which evaluated as;
true ? false ? false ? 4 : 5 : 6 : 7
which evaluated as;
true ? false ? (false ? 4 : 5) : 6 : 7
which evaluated as;
true ? false ? 5 : 6 : 7
which evaluated as;
true ? (false ? 5 : 6) : 7
which evaluated as;
true ? 6 : 7
which returns 6.
Я пытался доказать это, вот так:
int Proof = ternaryTrueOne() ? ternaryTrueTwo() ? ternaryFalseOne() ?
ternaryTrueThree() ? ternaryFalseTwo() ? 2 : 3 : 4 : 5 : 6 : 7;
static bool ternaryTrueOne()
{
Console.WriteLine("This is ternaryTrueOne");
return true;
}
static bool ternaryTrueTwo()
{
Console.WriteLine("This is ternaryTrueTwo");
return true;
}
static bool ternaryTrueThree()
{
Console.WriteLine("This is ternaryTrueThree");
return true;
}
static bool ternaryFalseOne()
{
Console.WriteLine("This is ternaryFalse");
return false;
}
static bool ternaryFalseTwo()
{
Console.WriteLine("This is ternaryFalseTwo");
return false;
}
В этом случае это будет оцениваться таким же образом. Правильно? Это означает, что ternaryfalsetwo будет сначала писать в консоль. Но это не так. Это не пишет вообще. Это на самом деле работает так, и я написал троичное выражение как оператор if. Он работает слева направо и не должен оценивать остальную часть кода. Все остальные утверждения недоступны после первого ложного утверждения.
private static int Proof2()
{
if (ternaryTrueOne())
{
if (ternaryTrueTwo())
{
if (ternaryFalseOne())
{
if (ternaryTrueThree())
{
if (ternaryFalseTwo())
{
return 6;
}
else
{
return 7;
}
return 5;
}
else
{
return 6;
}
return 4;
}
else
{
return 5;
}
return 3;
}
else
{
return 4;
}
return 2;
}
else
{
return 3;
}
}
Был ли первоначальный ответ неверным? Что на самом деле означает правильная ассоциативность?
2 ответа
Поскольку троичный условный оператор имеет свое место в таблице приоритетов операторов (т.е. ни один другой оператор не имеет точно такой же приоритет, как он), правило ассоциативности применяется только при устранении неоднозначности условного оператора от другого.
Ассоциативность справа налево означает, что неявные скобки находятся вокруг самой правой троицы.
То есть,
a ? b : c ? d : e
эквивалентно
a ? b : (c ? d : e)
,
https://en.wikipedia.org/wiki/Operator_associativity - это полезная ссылка.
Ассоциативность и порядок исполнения взаимосвязаны, но не идентичны.
Ассоциативность существует независимо от любого выполнения - она определяется в математике, которая состоит исключительно из чистых функций, поэтому "порядок выполнения" не имеет никакого отношения к результату.
Порядок выполнения в троичном операторе в C# очень прост:
- Оценить состояние
- Оцените trueBranch, если условие истинно, или falseBranch, если условие ложно
Вы можете представить правила ассоциативности как "где принадлежат парены".
Учти это:
a ? b : c ? d : e
Если мы ничего не знаем о том, как работает ассоциативность, мы можем увидеть различные способы введения паренов:
- (a? b: c)? д: е
- а? B: (C? D: E)
Первый подход является левоассоциативным, второй - правоассоциативным
Не должно быть трудно понять, что два подхода приводят к разным результатам. Например,
(true ? true : false) ? false : false // false
true ? true : (false ? false : false) // true
Теперь, если переписать это в отдельном if
операторы (которые обычно не так, как троичные на самом деле выполняется, но это будет делать), вы получите это:
if (a)
{
return b;
}
else
{
if (c) return d;
else return e;
}
Оценка такая же, как с простой троичной:
- Оценить состояние
a
- Если это правда, оцените и верните
b
; в противном случае продолжить - Оценить состояние
c
- Если это правда, оцените и верните
d
; в противном случае оценить и вернутьe
Это должно сделать очевидным, как работает ассоциативность и порядок выполнения. Таким образом, мы можем закончить поездку и объяснить ваш пример.
У нас есть ряд вложенных условных выражений:
a ? b ? c ? 0 : 1 : 2 : 3
Как ассоциативность применяется здесь? Это не так. Там нет ассоциативной операции здесь! Что вы делаете, это:
a ? (b ? (c ? 0 : 1) : 2) : 3
Другого способа поставить парены нет - это единственный возможный способ разбора операторов.
Поскольку троичный оператор, в общем, троичный, это немного трудно увидеть, но это становится более очевидным, когда вы переписываете его как функцию (например, "не встроенный оператор"):
var f = (a, b, c) => a ? b : c;
f(a, f(b, f(c, 0, 1), 2), 3);
Нет никакой двусмысленности - нет альтернативного способа разобрать это выражение.
Показывать ассоциативность с бинарными операторами немного проще, поэтому рассмотрим следующий сценарий:
a - b - c
Если вы не знаете об ассоциативности -
Вы можете увидеть два альтернативных способа поставить паренсов - (a - b) - c
а также a - (b - c)
, который может дать вам два разных результата. Таким образом, -
не является ассоциативным
Сравнить с +
который является ("полностью") ассоциативным (a + b) + c
а также a + (b + c)
это точно то же самое.