Приведение типов для типа Option - PullRequest
0 голосов
/ 09 июля 2020

Я новичок в ie в Rust из Python. Я считаю, что это базовый c вопрос, но я слишком новичок, чтобы найти ответ по таким ключевым словам, как Type Casting Option .

In Python, чтобы средство проверки типов знало, что возврат тип не Optional[int] + int, мы можем адресовать assert logi c, чтобы принудительно использовать проверку типов. Знайте, что x никогда не будет None после строки assert.

from typing import Optional


def add_one(x: Optional[int] = None) -> int:
    if x is None:
        x = 0
    assert x is not None
    return x + 1


if __name__ == '__main__':
    add_one(0)    # 1
    add_one()     # 1
    add_one(999)  # 1000

В Rust, предполагая, что интерфейс такой же, как добиться того же? А именно, как заставить компилятор знать, что тип x больше не Option?

fn add_one(mut x: Option<i32>) -> i32 {
    if x == None {
        x = Some(0);
    }
    return x + 1;
}

fn main() {
    add_one(Some(0));
    add_one(None);
    add_one(Some(999));
}

Вот сообщение об ошибке:

error[E0369]: binary operation `+` cannot be applied to type `std::option::Option<i32>`
 --> tmp.rs:5:14
  |
5 |     return x + 1;
  |            - ^ - {integer}
  |            |
  |            std::option::Option<i32>
  |
  = note: an implementation of `std::ops::Add` might be missing for `std::option::Option<i32>`

Обратите внимание, что я пробовал кое-что например, добавление другой переменной с типом i32 (let y: i32 = x;), но это не сработало и со следующим сообщением.

error[E0308]: mismatched types
 --> tmp.rs:5:22
  |
5 |     let y: i32 = x;
  |                  ^ expected i32, found enum `std::option::Option`
  |
  = note: expected type `i32`
             found type `std::option::Option<i32>`

Ответы [ 2 ]

3 голосов
/ 09 июля 2020

Используйте unwrap_or:

fn add_one(x: Option<i32>) -> i32 {
    x.unwrap_or(0) + 1
}

fn main() {
    assert_eq!(1, add_one(Some(0)));
    assert_eq!(1, add_one(None));
    assert_eq!(1000, add_one(Some(999)));
}
1 голос
/ 09 июля 2020

А именно, как сделать так, чтобы компилятор знал, что тип x больше не является Option?

Средство проверки типов в Rust не обязательно должно быть совместимо с несколько хитроумными шаблонами использования, поэтому для этого нужно переопределить x как больше не вариант, например:

fn add_one(mut x: Option<i32>) -> i32 {
    let x = if let Some(v) = x {
        v
    } else {
        0
    };
    return x + 1;
}

или более уродливый и менее эффективный (но, возможно, ближе к Python):

fn add_one(mut x: Option<i32>) -> i32 {
    let x = if x == None {
        0
    } else {
        x.unwrap()
    };
    return x + 1;
}

Обратите внимание, что у вас нет , чтобы затенять x, поэтому вы можете также let y вместо этого. Здесь, вероятно, было бы чище.

Но, как указал Бой ios, Rust предоставляет утилиты для такого рода вариантов использования, например unwrap_or, map_or, ...

...