Каков самый быстрый способ преобразования значения &u8 в значение u16 в Rust?

Я прохожу https://rust-exercisions.com/ и в одном из упражнений вы реализовали тип Saturating16. В частности, один из тестов требует умения составить Saturating16 из &u8.

Вот реализация, которую я использовал:

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct SaturatingU16 {
    value: u16,
}


impl From<&u8> for SaturatingU16 {
    fn from(value: &u8) -> Self {
        SaturatingU16 {
            value: (*value).into(),
        }
    }
}

Меня интересует вот что: value: (*value).into().

Здесь я предполагаю, что разыменование *value неявно скопирует базовый &u8 в u8, а затем .into() создаст новый u16. Во-первых, верно ли это предположение?

Во-вторых, если все правильно, похоже, что разыменование — это накладные расходы, которые нам не нужны — мы создаем два значения и сразу же выбрасываем одно из них. Есть ли способ перейти напрямую из &u8 в u16?

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

Ry- 08.06.2024 09:04
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
1
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У вас есть самый быстрый способ.

Ссылка — это тип указателя, поэтому в какой-то момент должно произойти разыменование (то есть загрузка), чтобы получить указанное значение. Этот шаг не является «накладными».

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

Генерация сборки x86 от &u8 до u16 дает следующее:

#[no_mangle]
pub fn convert(num: &u8) -> u16 {
    (*num).into()
}
convert:
    movzbl  (%rdi), %eax
    retq

Это преобразование можно было выполнить с помощью одной инструкции (комбинация загрузки байтов и расширения нулями).

Другие вопросы по теме