Как писать код Rust с помощью ChatGPT и Kani

Узнайте, как писать код Rust с помощью ChatGPT и доказать его достоверность с помощью Kani. Kani — это инструмент автоматической проверки рассуждений Rust, предназначенный для проверки кода, созданного с использованием ChatGPT.

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

Хотя ChatGPT может генерировать для вас эти ответы, нет никакой гарантии, что код будет работать или не будет содержать ошибок, даже если он может показаться действительным кодом. Это может привести к сбоям в программном обеспечении или пропущенным проблемам в конечном проекте.

В подобных ситуациях пригодятся инструменты проверки кода, такие как Kani.

Кани использует автоматизированное рассуждение — область информатики, которая пытается доказать, что возможно с системой, а что невозможно. Это позволяет за секунды обнаруживать проблемы в вашем коде, на решение которых вручную или с помощью модульного тестирования потребовалось бы несколько часов или даже больше.

В этом руководстве мы научимся писать код Rust с помощью ChatGPT и подтверждать его валидность с помощью Kani. Мы рассмотрим:

  • Настройка Kani в вашем проекте Rust
  • Использование Kani для проверки кода ChatGPT на Rust
  • Использование ChatGPT для исправления ошибок кода
  • Еще один пример использования Kani и ChatGPT.
  • Что следует учитывать при использовании Кани

Чтобы продолжить, у вас должен быть установлен Rust. Я предлагаю вам использовать Rustup для быстрой установки Rust для вашей ОС. Запустите команду ниже, чтобы установить Rust с помощью Rustup:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Эта установка займет некоторое время, но она будет включать в себя последнюю версию Rust и дополнительные инструменты, которые вам понадобятся, включая Cargo, менеджер пакетов Rust. После завершения запустите его, cargo --versionчтобы убедиться, что установка прошла успешно.

Настройка Kani в вашем проекте Rust

Чтобы использовать Kani, нам нужно его установить. Кани требует, чтобы у вас был Python v3.6 или новее и Rust v1.58 или новее. Мы просто установим последние версии Rust и Python.

Если у вас нет Python, начните с установки Python с официального сайта вашей операционной системы. Затем выполните следующие команды для установки и настройки Kani:

cargo install --locked kani-verifier
cargo kani setup

В приведенном выше коде первая команда создаст и разместит kaniдвоичные cargo-kaniфайлы в формате ~/.cargo/bin. Второй загрузит компилятор Kani и другие необходимые зависимости, а затем поместит их в ~/.kani/.

После завершения установки убедитесь, что установка прошла успешно, создав файл app.rsи добавив в него этот фрагмент кода:

#[kani::proof]
fn main() {
    assert!(1 == 2);
}

Затем запустите kani app.rsна своем терминале. Результат, который вы видите, должен выглядеть так, как показано ниже. Это означает, что Kani установлен и работает должным образом:

Теперь, когда у нас установлены Rust и Kani, давайте рассмотрим, как можно использовать Kani для проверки кода Rust, сгенерированного ChatGPT.

Использование Kani для проверки кода ChatGPT на Rust

Допустим, вы хотите разработать функцию для финтех-приложения с использованием Rust, которая позволит пользователям безопасно переводить средства между разными учетными записями.

Чтобы задать вопрос ChatGPT, мы хотим быть более точными и более описательными, поэтому мы будем использовать подсказку, подобную приведенной ниже:

Привет, ChatGPT, не могли бы вы написать на Rust программу, представляющую базовую банковскую систему? Система должна иметь возможность создавать отдельные учетные записи с именами и балансами. Он также должен иметь возможность переводить средства между счетами. В случае недостаточности средств должно появиться сообщение об ошибке. Наконец, продемонстрируйте сценарий, в котором средства успешно переводятся между двумя счетами, а затем отображаются их окончательные балансы.

Вот пример ответа, который мы можем получить:

Важно отметить, что для этого примера я использовал ChatGPT 4, который является более продвинутым по сравнению с ChatGPT 3.5.

Если вы попытаетесь запустить этот код, каков, по вашему мнению, будет результат? Не думайте об этом слишком много — все должно пройти успешно, а результат должен выглядеть так:

Но всегда ли этот код работает так, как ожидалось? Пока что он выполняется без сбоев. Конечно, вы можете написать модульные тесты для некоторых предсказуемых ошибок, но давайте посмотрим правде в глаза: может быть бесчисленное множество сценариев, о которых вы еще не подумали.

Именно здесь в игру вступают такие инструменты, как Kani, которые помогают нам решать эти неожиданные крайние случаи. Пришло время протестировать наш код, сгенерированный ChatGPT, с помощью Кани.

Для тестирования с помощью Kani мы заменим значение баланса на kani::any(), что, по сути, позволит kaniанализировать код во всех возможных случаях. Если мы запустим его с начальным статическим значением, он kaniвсегда будет возвращать успешный результат, а это не то, что нам нужно.

Вот как мы изменим код для использования kani:

#[kani::proof]
fn main() {
    let mut account1 = Account {
        name: "Obiageli".to_string(),
        balance: kani::any(),
    };
    let mut account2 = Account {
        name: "Emeka".to_string(),
        balance: kani::any(),
    };
    process_transfer(&mut account1, &mut account2, 100);
    println!("{}'s account balance: {}, and {}'s account balance: {}", account1.name, account1.balance, account2.name, account2.balance)
}

Во-первых, нам нужно добавить kani::proofк нашей основной функции. Это рассказывает kaniо входных данных, которые мы используем в этой функции, и делает функцию осведомленной о Кани.

Затем мы запускаем наш код, используя kani. Для этого просто введите cargo kani. В нашем случае вы должны увидеть много successсообщений, одно failи несколько предупреждений. Вот пример того, как может выглядеть анализ Кани:

shell
...
Check 25: std::intrinsics::is_nonoverlapping::<u8>.assertion.1
         - Status: UNREACHABLE
         - Description: "attempt to subtract with overflow"
         - Location: ../../../../runner/.rustup/toolchains/nightly-2023-04-30-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/intrinsics.rs:2547:43 in function std::intrinsics::is_nonoverlapping::<u8>

Check 26: std::intrinsics::is_nonoverlapping::<u8>.assertion.2
         - Status: UNREACHABLE
         - Description: "attempt to subtract with overflow"
         - Location: ../../../../runner/.rustup/toolchains/nightly-2023-04-30-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/intrinsics.rs:2547:74 in function std::intrinsics::is_nonoverlapping::<u8>

SUMMARY:
 ** 1 of 155 failed (3 unreachable)
Failed Checks: attempt to add with overflow
 File: "/Users/{username}/Development/logrocket/usekani/src/main.rs", line 38, in process_transfer

VERIFICATION:- FAILED
Verification Time: 0.8893617s

Summary:
Verification failed for - main
Complete - 0 successfully verified harnesses, 1 failures, 1 total.

Как мы видим из сообщений об ошибках, существует вероятность того, что наша программа может столкнуться с различными формами ошибок переполнения.

Интересно, что при обработке таких ошибок Rust работает по-разному в режимах отладки и выпуска. В режиме отладки Rust выдает ошибки переполнения, а в режиме выпуска вместо ошибки вы увидите возврат 0. Это отличается от таких языков, как C.

Даже если это так, важно решить эти проблемы переполнения, поскольку они могут привести к неожиданному поведению. К счастью, мы можем использовать ChatGPT, чтобы помочь нам решить проблему.

Использование ChatGPT для исправления ошибок кода

Вам просто нужно предоставить сообщения об ошибках и попросить ChatGPT исправить код на основе возвращенных ошибок. Лично для меня ChatGPT признал, что произошла ошибка, и дал объяснение:

Затем, после объяснений, он дал решение ниже:

```rust
struct Account {
    name: String,
    balance: u32,
}
fn process_transfer(from_account: &mut Account, to_account: &mut Account, amount: u32) {
    if from_account.balance < amount {
        println!("Error: insufficient funds in account {}", from_account.name);
        return;
    }

    if to_account.balance.checked_add(amount).is_none() {
        println!("Error: transfer would result in an overflow in account {}", to_account.name);
        return;
    }

    from_account.balance -= amount;
    to_account.balance += amount;
}
#[kani::proof]
fn main() {
    let mut account1 = Account {
        name: "Obiageli".to_string(),
        balance: kani::any(),
    };
    let mut account2 = Account {
        name: "Emeka".to_string(),
        balance: kani::any(),  // just for demonstration purposes
    };
    process_transfer(&mut account1, &mut account2, 100);
    println!("{}'s account balance: {}, and {}'s account balance: {}", account1.name, account1.balance, account2.name, account2.balance)
}
```

Не изменяя код дальше, мы проверим его, запустив cargo kani. Ответ полностью зеленый — другими словами, успешный — как показано ниже:

SUMMARY:
 ** 0 of 167 failed (3 unreachable)

VERIFICATION:- SUCCESSFUL
Verification Time: 0.91400814s

Complete - 1 successfully verified harnesses, 0 failures, 1 total.

Иногда вам может потребоваться просмотреть код самостоятельно (на самом деле, вы всегда должны это делать) и изменить некоторые части там, где это необходимо. Проверка кода вручную может помочь вам избежать ситуаций, когда ChatGPT уверенно, но ошибочно делает ошибочные предположения, также называемые галлюцинациями.

Например, если база кода большая, лучше разделить код на части; если функция слишком велика, это может стать проблемой само по себе.

Еще один пример использования Kani и ChatGPT.

Давайте рассмотрим другой сценарий, в котором мы хотим получить элемент из вектора на основе его положения в векторе. Например, предположим, что вы предоставляете функции вектор и индекс элемента в векторе.

Когда мы просим ChatGPT сгенерировать код для решения этой проблемы, он должен сгенерировать что-то вроде кода ниже:

fn get_value(vec: &Vec<i32>, index: usize) -> Option<&i32> {
    if vec.is_empty() {
        None
    } else {
        Some(&vec[index])
    }
}

fn main() {
    let vec = vec![1, 2, 3];
    match get_value(&vec, 0) {
        Some(value) => println!("{}", value),
        None => println!("No value found."),
    }
}

Вы можете задаться вопросом: «В чем проблема с этим кодом?»

Конечно, большую часть времени он работает так, как и ожидалось, но в некоторых случаях его не хватает. Сможете ли вы угадать, когда?

Если вы предполагаете, что пользователь вводит индекс, выходящий за пределы допустимого, вы правы! У нас в векторе всего три элемента с индексом от нуля до двух. Если пользователь вводит 3, произойдет ошибка выхода за границы.

Кажется, такую ​​ошибку легко обнаружить, не так ли? Но иногда вы не можете обнаружить проблему достаточно рано. В таких ситуациях может помочь такой инструмент проверки, как Kani. Давайте запустим код через Kani и посмотрим, что мы сможем получить.

Замените предыдущий код или закомментируйте его и вставьте приведенный выше пример, а затем запустите его, cargo kaniчтобы получить результат, который должен выглядеть примерно так:

Мы можем просто скопировать сообщение об ошибке и попросить ChatGPT исправить его, и он даст нам исправление. Вот ответ, который я получил от ChatGPT:

Благодаря этому мы успешно использовали ChatGPT для генерации кода, а затем исправили ошибки в сгенерированном коде, и все это благодаря Кани.

Что следует учитывать при использовании Кани

Хотя Kani может повысить общую эффективность вашего кода и снизить вероятность возникновения ошибок, имейте в виду, что он также может увеличить сложность и время разработки.

Использование Kani может увеличить общую трудоемкость написания кода на Rust, поскольку оно имеет свою сложность. Вам придется иметь дело с компилятором Rust, написанием тестов и другими частями жизненного цикла разработки программного обеспечения.

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

Заключительные слова

ChatGPT и остальные генераторы кода искусственного интеллекта великолепны, но они не идеальны. Однако мы можем использовать их для создания более качественного программного обеспечения в рекордно короткие сроки.

В этой статье мы коснулись того, как можно использовать Kani, инструмент автоматической проверки рассуждений на Rust, для проверки кода, сгенерированного с помощью ChatGPT. Совместное использование этих инструментов может помочь вам создавать более качественные и безошибочные программы.

Хотя инструменты статического анализа, такие как ржавчина-анализатор, могут в значительной степени помочь вам при написании кода Rust, инструменты проверки, такие как Kani , могут даже помочь вам в дальнейшем. Использование комбинации инструментов разработчика искусственного интеллекта позволит вам писать код, которым вы будете гордиться, и повысите свою продуктивность во время работы.

Удачного взлома!

Источник: https://blog.logrocket.com .

#rust #chatgpt 

1.05 GEEK