Есть ли издержки в подходе к вызову методов в стиле Rust по сравнению с обычным использованием функций в других языках системного программирования, таких как C? - PullRequest
0 голосов
/ 13 июня 2019

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

let secret_number = rand::thread_rng().gen_range(1, 101);

Я предполагаю, что случайное целое число генерируется после создания экземпляра структуры rand::ThreadRng путем вызова ее метода.

Разве для производительности не лучше просто использовать функции, как в C?Поскольку Rust позиционирует себя как язык системного программирования, и, если я прав в своей гипотезе, этот выбор в пользу создания структур и использования их методов представляется довольно неоптимальным.

1 Ответ

5 голосов
/ 13 июня 2019

Есть ли издержки в подходе к вызову метода в стиле Rust по сравнению с [...] C?

номер

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

Не лучше ли для производительности просто использовать функции, как в C?

Методы являются функциями.

Метод Rust концептуально аналогичен функции C, принимающей указатель:

Rust

struct Foo {
    a: i32,
}

impl Foo {
    fn add(&self, b: i32) -> i32 {
        self.a + b
    }
}

C

struct Foo {
    int a;
};

int Foo_add(struct Foo *self, int b) {
    return self->a + b;
}

Здесь нет важного различия между двумя языками.

Rust имеет свободные функции, а также связанные функции; если вам не нужна ссылка на данные, вам не нужно:

Rust

struct Foo {
    a: i32,
}

// Free function
fn foo() -> Foo { 
    Foo { a: 42 }
}

impl Foo {
    // Associated function
    fn new() -> Foo {
        Foo { a: 99 }
    }
}

C

struct Foo {
    int a;
};

struct Foo foo() {
    struct Foo foo = { 42 };
    return foo;
}

struct Foo Foo_new() {
    struct Foo foo = { 99 };
    return foo;
}

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

Rust

// Zero size
struct Foo;

impl Foo {
    fn add_one(&self, b: i32) -> i32 {
        b + 1
    }
}

C

int Foo_add_one(int b) {
    return b + 1;
}

создание структур и использование их методов представляется довольно неоптимальным

Создание структур и связанных методов распространено в C-коде. Я бы сказал, что это, скорее всего, преобладающий стиль кодирования; Я не знаю, почему вы говорите, что это неоптимально.


Ваш пример не подходит для сравнения, потому что вы не предоставили любой C-код, тем более что-то эквивалентное. ThreadRng выполняет много работы, чтобы обеспечить лучший опыт для генерации случайных чисел:

ThreadRng использует ReseedingRng, оборачивая тот же PRNG, что и StdRng, который повторяется после генерации 32 МБ случайных данных. Один экземпляр кэшируется для каждого потока, и возвращенный ThreadRng является ссылкой на этот экземпляр - следовательно, ThreadRng не является ни Send, ни Sync, но безопасен для использования в одном потоке. Этот ГСЧ посеян и посеян через EntropyRng по мере необходимости.

«Традиционный» генератор случайных чисел (rand) имеет глобальное состояние (что, как правило, плохо), но концептуально выглядит так:

struct RngState {
    int whatever_goes_here;
};

static struct RngState GLOBAL_STATE = { 0 };

int rand_with_state(struct RngState *state) {
    return state->whatever_goes_here++;
}

int rand() {
    return rand_with_state(&GLOBAL_STATE);
}

Обратите внимание, что все еще использует указатель на данные .

...