Часть примера кода в этой статье находится вyoungjuning/learn-rust, статья была впервые опубликована вОфициальный сайт Луожу
Языки имеют схожие основные функции, такие как такие понятия, как переменные, примитивные типы, функции, аннотации и поток управления. Но у каждого языка есть свои уникальные концепции, и эта статья предназначена для записи уникальных концепций Rust, с которыми я столкнулся в процессе изучения синтаксиса Rust.
Переменные и изменчивость
Переменные в Rust по умолчанию неизменяемы. Язык Rust предоставляет эту концепцию, чтобы вы могли безопасно и легко писать сложный, даже параллельный код. Конечно, Rust также предоставляет методы, позволяющие использовать изменяемые переменные.
// main.rs
fn main() {
let x = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x)
}
x = 6
Это относится к повторяющемуся присваиванию, поэтому выполнитеcargo run
Компиляция не пройдет:
Мы можем сделать это, добавив перед объявленным именем переменнойmut
ключевое слово, чтобы сделать его изменяемым. В дополнение к тому, чтобы сделать значение переменной изменяемым,mut
Это также намекает тому, кто читает код, что другой код может изменить значение этой переменной.
Разница между константами и переменными
- мы не можем использовать
mut
ключевое слово для изменения переменной. Константа не только неизменяема по умолчанию, она неизменна всегда. - вам нужно использовать
const
ключевое слово вместоlet
ключевое слово для объявления константы. - Во время объявления вы должны явно аннотировать тип значения.
- Константы могут быть объявлены в любой области видимости, даже глобальной. Это полезно, когда на значение нужно ссылаться в разных частях кода.
- Вы можете привязать константу только к константному выражению, вы не можете привязать возвращаемое значение функции или другое значение, которое необходимо вычислить во время выполнения, к константе.
Мы договорились и в просторечии используем заглавные буквы с разделителями подчеркивания для имени константы и вставляем символы подчеркивания в значения для улучшения читабельности:
const MAX_POINTS: u32 = 100_000;
Спрятать
В Rust вновь объявленная переменная может перезаписать старую переменную с таким же именем Мы описываем это явление так: первая переменная затеняется второй переменной. Это означает, что когда мы будем использовать это имя позже, оно будет ссылаться на вторую переменную. мы можем повторно использоватьlet
ключевое слово и присвоение того же имени, чтобы скрыть переменные:
fn main() {
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x)
}
Как показано на рисунке ниже, мы видим, что эта функция не существует в JavaScript:
Механизмы сокрытия и переменные, объявленные какmut
разница:
- если не использовать
let
Переназначение этой переменной приведет к ошибке компиляции. используяlet
, мы можем выполнить ряд операций преобразования над этим значением и позволить переменной сохранить свою неизменность после завершения операции. - из-за многократного использования
let
Ключевые слова создают новые переменные, поэтому мы можем повторно использовать имя переменной при изменении ее типа.
тип данных
Компилятор RUST может автоматически определить тип переменной на основе того, как мы связываем и используем значение переменной. Но в сценариях, которые нельзя вывести автоматически, необходимо явно добавить аннотацию типа.
Скалярный тип (скалярный)
скалярТип — это общий термин для одного типа значения. В Rust встроено четыре основных скалярных типа: целые числа, числа с плавающей запятой, логические значения и символы. Это похоже на примитивные типы в JavaScript.
Целочисленный тип
Целые числа — это числа без дробной части.
длина | подписал | неподписанный |
---|---|---|
8 bit | i8 (от -128 до 127) | U8 (от 0 до 255) |
16 bit | i16 (от -32768 до 32767) | u16 (от 0 до 65535) |
32 bit | i32 (по умолчанию) | u32 |
64 bit | i64 | u64 |
arch | isize | usize |
Isize и usize — это специальные целочисленные типы, длина которых зависит от целевой платформы, на которой работает программа. В 64-битной архитектуре они 64-битные, а в 32-битной архитектуре — 32-битные.
можно использовать
_
в качестве разделителя для облегчения чтения, например.1_000
как выбрать:
- Если вы сомневаетесь, выводимый по умолчанию тип Rust i32 для целочисленных литералов обычно является хорошим выбором: в большинстве случаев это самая быстрая операция.
- Еще два специальных целочисленных типа
usize
иisize
в основном используется как индекс для некоторых коллекций
тип с плавающей запятой
- числа одинарной точности с плавающей запятой (
f32
) - Числа двойной точности с плавающей запятой (
f64
)(дефолт)
Поскольку двойная и одинарная точность эффективно работают на современных процессорах, но имеют более высокую точность, в Rust тип литералов с плавающей запятой по умолчанию устанавливается на f64.
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
Логическое значение
Как и в Go, логический тип Rust имеет только два возможных значения:true
иfalse
. по сравнению с Javascriptfalse
,0
,NaN
,''
,null
,undefined
6 можно превратить вfalse
Это действительно экономит силы мозга.
fn main() {
let t = true;
let f: bool = false // 附带了显式类型标注的语句
}
тип персонажа
В ржавчинеchar
Типы используются для описания самых основных одиночных символов языка. должны знать о том,char
Типы указываются с помощью одинарных кавычек, в отличие от строк, которые указываются с использованием двойных кавычек.
составной тип
Составные типы могут объединять несколько значений разных типов в один тип. Rust предоставляет два встроенных основных составных типа: кортежи и массивы.
тип кортежа
- Кортежи могут объединять несколько значений других разных типов.
- Кортежи имеют фиксированную длину, мы не можем увеличивать или уменьшать количество элементов после объявления
Создайте кортеж:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
- поместите некоторые значения столбца, разделенные запятыми, в пару круглых скобок
- Значение в каждой позиции кортежа имеет тип, и типы не обязательно должны быть одинаковыми.
Вышеприведенный абзац приводит к исполнениюcargo run
Будет предупреждение о компиляции:
Это означает, что если вы намеренно объявляетеunused variable
, затем поставьте перед именем переменной знак подчеркивания, чтобы игнорировать предупреждение
Ценность:
1. Деструктуризация: используйте сопоставление с образцом для деконструкции кортежей:
fn main() {
let tup = (500, 6.4, 1);
let (_x, y, _z) = tup;
println!("The value of y is: {}", y);
}
2. По индексу и с помощью точек (.
) для доступа к значениям в кортеже:
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
тип массива
массив (массив)
Массивы часто являются полезным инструментом, когда вы не хотите выделять место для данных в стеке, а не в куче, или когда вы хотите убедиться, что у вас всегда есть фиксированное количество элементов.
- В отличие от кортежей, каждый элемент массива должен быть одного типа.
- Массивы в Rust имеют фиксированную длину, и после их объявления их размер нельзя изменить произвольно, в отличие от других языков.
В Rust вы можете создать массив, поместив значения через запятую в квадратные скобки:
fn main() {
let a = [1, 2, 3, 4, 5]
}
Чтобы записать тип массива, вам нужно использовать пару квадратных скобок и заполнить квадратные скобки типом всех элементов в массиве, точкой с запятой и количеством элементов в массиве, как следует:
let a: [i32, 5] = [1, 2, 3, 4, 5]
Создайте массив с такими же элементами:
let a = [3; 5]
отa
Именованный массив будет иметь 5 элементов, все из которых имеют одинаковое начальное значение 3. Это письмо эквивалентноlet a = [3, 3, 3, 3, 3]
.
Доступ к элементам массива:
Массивы состоят из блока памяти, размещенного в стеке, и вы можете получить доступ ко всем элементам массива по индексу:
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
неправильный доступ к массиву
fn main() {
let a = [1, 2, 3, 4, 5];
let index = 10;
let element = a[index];
println!("The value of elements is: {}", element)
}
существуетRust PlaygroundЗапустив этот код, компилятор сообщает нам, что эта операция завершится сбоем во время выполнения. Причина в том, что индекс выходит за пределы (распространенная ошибка Java), длина массива равна 5, а индекс, который мы дали, равен 10.
Многие низкоуровневые языки не имеют подобных проверок, и если вы попытаетесь использовать недопустимый индекс, вы получите доступ к недопустимому блоку памяти (в JavaScript он возвращает
undefined
)
Динамический массив (вектор)
Динамический массив — это структура коллекции, похожая на массив, но позволяющая пользователю свободно регулировать длину массива. Если вы не уверены, использовать ли массив или динамический массив, сначала используйте динамический массив. Динамические массивы относятся к расширенному синтаксису и в этой статье не рассматриваются, более подробный анализ будет опубликован позже.
функция
-
main
Функции — это то, с чего начинается большинство программ. - использовать
fn
ключевое слово для объявления новой функции. - Код Rust использует змеиный регистр в качестве стиля для нормализации имен функций и переменных. В именах змей используются только строчные буквы, а слова разделяются символами подчеркивания.
fn main () {
println!("Hello world!");
another_function();
}
fn another_function() {
println!("Another function");
}
параметр функции
Параметры функции представляют собой особый тип переменных и считаются частью сигнатуры функции. Когда у функции есть параметры, вам необходимо указать определенные значения для этих переменных при вызове функции.
fn main() {
another_function(5);
}
fn another_function(x: i32) {
println!("The value of x is: {}", x)
}
Как и в Go, в сигнатурах функций Rust вы должны явно объявлять тип каждого параметра.
Как и другие языки программирования, Rust использует,
для разделения нескольких параметров:
fn main() {
another_function(5, 6);
}
fn another_function(x: i32, y: i32) {
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
Операторы и выражения в телах функций
Поскольку Rust — это язык, основанный на выражениях, он отличает оператор от выражения как два разных понятия. Операторы — это те инструкции, которые выполняют операцию, но не возвращают значение, а выражения — это те, которые выполняют вычисления и в результате получают значение. Это не то же самое для других языков:
В C, Ruby, JavaScriptvar x = y = 6
Этот оператор присваивания возвращает присвоенное значение, но он не работает в Rust.
Стоит отметить, что в следующем кодеx+1
это выражение.
fn main() {
let x = 5;
let y = {
let x = 3;
x + 1
}
println!("The value of y is: {}", y);
}
Но если мы поставим точку с запятой в конце выражения, код станет оператором и не вернет никакого значения.
возвращаемое значение функции
- В Rust возвращаемое значение функции равно значению последнего выражения в теле функции.
- В отличие от других языков программирования, функции в Rust
return
оператор не требуется, просто ключевое слово, используемое для раннего возврата. И большинство функций неявно возвращают финальное выражение. - нужно быть в тощей стрелке(
->
) после объявления его типа.
Последняя строка тела функции должна быть выражением без точки с запятой. Ниже приведен встречный пример:
fn main() {
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn plus_one(x: i32) -> i32 {
x + 1;
}
Попытка скомпилировать этот код приводит к следующему сообщению об ошибке:
Видно, что из-заx +1;
состоит в том, что выражение не имеет возвращаемого значения, а тело функции неявно возвращает пустой кортеж (()
), что, в свою очередь, вызывает время компиляцииmismatched types
Ошибка. Совет, данный компилятором, состоит в том, чтобы удалитьx +1;
Точка с запятой в заявлении.
поток управления
если выражение
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false")
}
}
- Как и в Go, условия не нуждаются в скобках.
- Условные выражения в коде должны создавать
bool
значение типа, иначе будет вызвана ошибка компиляции. - В отличие от таких языков, как Ruby или JavaScript, в Rust нет неявных преобразований.
существуетlet
используется в заявленииif
так как if
является выражением, поэтому мы можем тогдаlet
Правая часть оператора использует его для генерации значения.
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!("The value of number is: {}", number);
}
- Значение, выдаваемое кодовым блоком, является значением последнего выражения в нем, а само число также может использоваться как выражение.
- весь
if
Значение выражения зависит от того, какой блок кода был выполнен. Это означает, что всеif
Все возможные значения, возвращаемые веткой, должны быть одного типа.
Используйте циклы для многократного выполнения кода
Rust предоставляет 3 вида циклов:loop
,while
иfor
петля петля
fn main() {
loop {
println!("again!")
}
}
При запуске этой программы, если мы вручную принудительно не выходим из программы, в противном случаеagain!
будет неоднократно выводиться на экран.
возвращаемое значение из цикла
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2
}
};
println!("The result is {}", result);
}
В приведенном выше коде мы добавляем значение, которое хотим вернуть, после выражения break, которое мы используем для завершения цикла.
пока условный цикл
fn main() {
let mut number = 3;
while number !=0 {
println!("{}!", number);
number = number - 1;
}
println!("LOFTOFF!!!")
}
while
Режим цикла заключается в оценке условия перед каждым выполнением тела цикла.Если условие истинно, выполняется фрагмент кода, а если условие ложно или встречается во время выполненияbreak
для выхода из текущего цикла. Этот режим может бытьloop
,if
,else
иbreak
Для этого используется комбинация ключевых слов.
Перебор коллекции с помощью цикла for
мы можем использоватьfor
Цикл для перебора каждого элемента в коллекции.
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("The value is: {}", element)
}
}
for
Безопасность и простота циклов делают циклы наиболее часто используемой конструкцией цикла в Rust. Большинство разработчиков Rust также предпочитают использовать циклы for.
В следующем примере мы взаимодействуем с Range в стандартной библиотеке для печати1
прибыть4
:
fn main() {
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!")
}
История не окончена
После поиска я не нашел группу по обмену Rust, поэтому я создал ее сам.
У Tuya Smart большое количество качественных НС, присоединяться могут все желающие, нужно добавить меня в WeChat yang_jun_ning, или прислать свое резюме прямо на почтуyoungjuning@aliyun.com