Как избежать использования негатива? - PullRequest
0 голосов
/ 13 октября 2018

Я перевожу часть (2000 строк) проприетарного кода на C в Rust.В C обычно указатель, индекс массива и т. Д. Обычно запускаются, пока они не отрицательны.В Rust, упрощенном до костей, это будет выглядеть примерно так:

while i >= 0 && more_conditions { 
    more_work;
    i -= 1;
}

Конечно, когда i равно usize, вы получаете переполнение от вычитания.Я научился обходить эту проблему, используя for циклы с .rev(), смещая мои индексы на единицу, или используя другой тип и приводя с as usize и т. Д.

Обычно это работает, и обычноЯ могу сделать его разборчивым, но код, который я изменяю, переполнен индексами, идущими навстречу друг другу, и в конечном итоге протестирован с i_low > i_high

Что-то вроде (в Rust)

loop {
    while condition1(i_low) { i_low += 1; }
    while condition2(i_high) { j_high -= 1; }
    if i_low > i_high { return something; }
    do_something_else;
}

Время от времени эта паника возникает, когда i_high проходит мимо 0.

Я вставил в код много j_high >= 0 &&, и он стал намного менее читабельным.

Как опытные программисты на Rust избегают usize переменных, идущих в -1?

  1. для циклов?for i in (0..size).rev()

  2. литье?i as usize, после проверки i < 0

  3. смещения вашей переменной на единицу и использования i-1 в безопасном режиме?

  4. дополнительные условия?

  5. ловить исключения?

Или вы в конечном итоге научились писать программы в таких ситуациях?


Пояснение: код C не нарушен - он предположительно находится в производстве в течение десяти лет, структурируя видео сегменты на нескольких серверах 24/7.Он просто не следует соглашениям Rust - он часто возвращает -1 в качестве индекса, он возвращается с -1 для низкого индекса обрабатываемого массива, и индексы все время становятся отрицательными.Все они обрабатываются до возникновения проблем - безобразно, но функционально.Примерно так:

incident_segment = detect_incident(array, start, end);
attach(array, incident_segment);
store(array, start, incident_segment - 1);
process(array, incident_segment + 1, end);

В приведенном выше коде каждый из трех результирующих вызовов может получить индекс сегмента, равный -1 (присоединить, сохранить) или выйти за пределы (процесс). Он обрабатывается, но послевызов.

Кажется, работает и мой код Rust.На самом деле, чтобы справиться с отрицательным использованием, я добавил дополнительную логику, которая сокращает количество рекурсий, поэтому он работает примерно так же быстро, как и код C (очевидно, быстрее, но это также потому, что я распределил вывод по несколькимдиски)

Проблема в том, что клиент не хочет полной перезаписи и хочет, чтобы «нативные» программисты могли проверять две программы друг против друга.Исходя из полученных ответов, я думаю, что использование i64 и приведение / теневое копирование по мере необходимости могут быть лучшим способом создания кода, который легко читать для «нативов».Что мне лично не должно нравиться ...

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Вероятно, я бы начал с использования saturating_sub_add для параллельной структуры):

while condition1(i_low) { i_low = i_low.saturating_add(1); }
while condition2(i_high) { j_high = j_high.saturating_sub(1); }

Вы должны быть осторожны, чтобы убедиться, что ваша логика обрабатываетзначение, насыщающее на нуле.Вы также можете использовать больше C-подобной семантики с wrapping_sub.

По правде говоря, не существует единого решения, подходящего для всех.Много раз, сложная логика становится проще, если вы немного ее абстрагируете или слегка переворачиваете.Вы не предоставили конкретных примеров, поэтому мы не можем дать полезных советов.Я решаю слишком много проблем с итераторами, так что это часто мое первое решение.

перехват исключений

Абсолютно нет.Это крайне неэффективно и не идиоматично.

0 голосов
/ 13 октября 2018

Если вы хотите сделать это идиоматически:

for j in (0..=i).rev() {
    if conditions {
        break;
    }
    //use j as your new i here
}

Обратите внимание на использование ..=i здесь в итераторе, это означает, что он будет фактически повторяться, включая i: [0, 1, 2, ..., i-1, i], в противном случаевы получите [0, 1, 2, ..., i-2, i-1]

В противном случае вот код:

while (i as isize - 1) != -2 && more_conditions { 
    more_work;
    i -= 1;
}

детская площадка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...