Что именно сравнивают операторы "==" и "is" в D? - PullRequest
1 голос
/ 27 октября 2019

Из книги «Программирование в D» я узнал, что оператору == необходимо получить доступ к объектам, чтобы оценить выражение слева и справа, прежде чем возвращать логическое значение. Таким образом, он не подходит для сравнения того, является ли объект null.

... оператору == может потребоваться обратиться к значениям элементов объектов и к тем, кто пытается получить доступ к элементамчерез потенциально нулевую переменную может вызвать ошибку доступа к памяти.

также

Равенство значений: оператор ==, встречающийся во многих примерах в книге, сравнивает переменные по их значениям. Когда говорят, что две переменные равны в этом смысле, их значения равны.

Итак, давайте попробуем следующее:

import std.experimental.all;

int[] arr = [1, 1, 2, 2, 3];
arr == arr.reverse.array; // --> true

Ну, это неожиданно. Например, в Scala это же выражение возвращает False.

Становится понятнее после проверки адреса памяти как arr, так и arr.reverse.array - он не меняется. Итак, теперь результат == имеет некоторый смысл, хотя можно было бы ожидать, что он будет сравнивать значения массивов, а не их адреса, верно?

Теперь давайте попробуем оператор is, который используется для сравнения объектассылки и должны использоваться, чтобы проверить, является ли объект null. Он также используется для сравнения переменных класса.

arr is arr.reverse.array; // --> false

Я ожидаю, что он также вернет true, поскольку он сравнивает ссылки. Что на самом деле здесь происходит? Почему is возвращает false, а == возвращает true?

1 Ответ

4 голосов
/ 27 октября 2019

== сравнивает значения. is сравнивает ссылки. Ваша большая ошибка - использование функции reverse.

http://dpldocs.info/experimental-docs/std.algorithm.mutation.reverse.html

Инвертирует r на месте.

Акцент мой. Это означает, что он изменяет содержимое оригинала.

Я подозреваю, что вы также неверно проверяете адрес памяти. Если вы используете &arr, вы сравниваете адрес локальных переменных, а не содержимое массива. Это не изменится, потому что это одна и та же локальная переменная, вы просто привязываетесь к другому массиву. Отметьте .ptr вместо &, и вы увидите, что он меняется - функция .array всегда выделяет для него новый массив.

Итак == пройдено, потому что обратное изменило левую часть на то жевремя! Это было не потому, что [1,2,3] == [3,2,1], а потому, что после вызова reverse, [1,2,3] сам был изменен на [3,2,1], который== [3,2,1]!.

Теперь о том, что на самом деле делают эти операторы: == проверяет некоторое абстрактное качество равенства. Это зависит от типа: оно может быть переопределено функциями-членами (именно поэтому вызов его для классов null проблематично) и часто выполняет сравнение между членами (например, элементы массива или элементы структуры).

is, с другой стороны, делает что-то намного проще: это битовое сравнение переменной напрямую, что ближе к абстрактному представлению о тождестве, но не совсем (как проходы int a = 3; int b = 3; assert(a is b);, потому что оба - 3, ноэто та же самая идентичность? нечеткая причина типа значения.)

is никогда не будет вызывать пользовательскую функцию и никогда не будет переходить к ссылкам на элементы, она просто сравнивает значения битов.

(что интересно, float.nan is float.nan также возвращает true, тогда как == не будет, опять же только потому, что он сравнивает битовые значения. Но не все nans имеют одинаковое битовое значение, поэтому он не заменяет isNaN в математическом модуле!)

...