Menu Close

Articles

Rust: Data types

Rust is a strongly typed programming language. That means after a variable is declared its data type remain the same during program execution. This restriction enable compiler to optimize the executable code and improve application efficiency. It is also useful to avoid runtime errors and improve developer experience.

Primitive Types

In Rust we have 3 primitive types. Signed, unsigned and floating precision numbers. Each type specify the number of bits, so it is much more easy to remember the type notation than in C language. 

Number types: { i8, i16, i32, i64, u8, u16, u32, u64, isize, usize, f32, f64 }

In Rust “i” numbers are integers. “u” numbers are unsigned. “f” numbers are floating point numbers. Variable size data types: isize and usize depends on machine architecture 32 or 64 bits.

Boolean types: true and false

In Rust the Boolean values are true and false like in Python and Ruby. The operators for Boolean expressions are like in C: { &&, ||,  !}.

Character types: Unicode

In Rust characters are Unicode not ASCII and occupy 4 bytes not 1 byte. A character is enclosed in single quotes like in C: { ‘0’,’1’….’a’,’b’,…. ‘π’, ‘α’, ‘β’, … ‘ω’ }

Variables

In Rust you must declare data type to create a variable using symbol :  and keyword let Variables are immutable in Rust unless you specify otherwise. Global variables can be defined using keyword static or const.

Example:

Notes: 

  • rust is using type inference the best it can to detect type for x
  • you can declare a variable and set initial value for it in a single statement

Expressions

Rust is using infix notation to create expressions. An expression is created using variables, constants and literals separated by operators. In previous example we use expression TEST+1  to calculate initial value for x. The result of expressions can be captured into a new variable using assign symbol =

You can create larger expressions from small expressions using parenthesis and operators. The order of operations is important. Operators { *,  / } have higher precedence than { +, – }.

Example:

(x + y) / 2 < (x + y)

Notes:

  • Previous expressions will evaluate true if x and y are both positive,
  • Relation operator < has lower precedence than arithmetic operator /,
  • It is a good practice to use spaces to separate operators of literals.

Numeric Operators

SymbolDescription
/division
*multiplication
%modulo (reminder of division)
+addition
subtraction

Update Operators

Most math operators and bitwise operators have an “update” version. The variable you use in left side of these operators must be mutable otherwise will generate compilation error:

SymbolDescription
=assign value
+=addition
-=subtraction
*=multiplication
/=division

Relation Operators

SymbolDescription
>relation operator: greater then
<relation operator: less then
==relation operator: is equal
!=relation operator: not equal (disjunctive)
>=relation operator: greater then or equal to
<=relation operator: less then or equal to

Logic Operators

SymbolDescription
!logical operator  “not” when is used as prefix
&&logical operator “and” sometimes called Boolean operator AND.
||logical operator “or” sometimes called Boolean operator OR.

Bitwise Operators

SymbolDescription
~but-wise operator “not”
&bit-wise operator “and”
|bitwise “or”  and pattern alternative
^bitwise exclusive “or”
<<left shift
>>right shift

Composite Types

The composite types are: { Arrays, Vectors, Slices, Strings, Tuples, Structs, Enums }. Some composite types have all members of the same type and function more like a data set. The structs and enums can have members of different data types and are more known as “records” in other languages.

Array

Collections of fixed size elements enclosed in square brackets [1,2,3] and separated by comma. First element can be found like in C using zero based subscript a[0] . The notation [T;N] is used to initialize an array with T using N members.

Example:

Vector

A vector is a smart array that can grow at run-time. It is implemented as a “generic” in the standard library. Vector is not as fast as Array but has more functionality. In other languages like Python this is known as a “List” and is implemented in the language core.

Example:

Note: Subscript index starts from 0 and is of type “usize”. Using other type will generate an error.

Slice

A slice is a view for a range of addresses in an array. You can create slice using “borrow” operator & and range operator ..

Example:

Notes:

  • slices are references to original array,
  • range operator .. exclude upper limit,
  • placeholder {:?} can be used for printing range elements.

Homework: run this example and investigate the result: slicing

Strings

The strings are enclosed in double quotes like this: “abc”. Strings are encoded UTF8 and not ASCII. That means one character occupy a variable number of bytes. Strings are not null terminated like in C and can contains several null characters inside.

Strings are of two kind: immutable and mutable. The default notation “abc” will create an immutable string. You can convert a non mutable string into a mutable string using function to_string(). You can convert a mutable string into immutable string using operator “&” in front of the string variable.

Example:

Warning: Previous example and some of the next examples are code fragments.  To run such code you need to wrap it in a function main(). Rust do not run statements outside functions. Also declarations using let are not supported outside functions. That will be a global variable that must be “static” otherwise is not supported.

Large strings

Strings can be created on multiple lines using continuation character “\”. If we do not then the new line and the indentation is included in the string and we may wish to avoid it. “\” will eliminate both end of lines and the spaces and will reduce them to one single space.

A new way to define strings in Rust is this notation from this example:

Notes:

A literal for example “hello” is not of type String. It is of type &str (that is a string slice). Therefore to make a proper string out of a literal you can use above notation: String::from("") that is better than using "".to_string() method.

Tuple

Tuple literal is enclosed in round brackets () like in Python. (1, 2, 3). A tuple can have characters and numbers mingled like: (1,’a’,”bcd”). The tuples are immutable collections. Interesting about tuples is the way a member is found using dot notation instead of subscript with brackets.

Example:

Struct

This is a composite data where every element has a name and a type. So it is like a record into a database table. Unlike tuple every element can be accessed by it’s name using dot notation not indexes. In the next example we show how to declare a complex type Point. The user defined types in Rust start with Capital letters by convention.

You can open this example live and run it: struct

Enumeration

The enumeration is created using enum keyword. It is very similar to a struct except that struct is data oriented while enum is based on symbols. The enumeration is created to somehow extend the language with new keywords. The enumeration elements can be used with symbol :: or can be imported in the current name space using the “use” keyword.

Example:

This example is available on-line here: enumeration

Note:

  • If you do not use all values in your enumeration you will get a compiler warning,
  • Directive #[derive(PartialEq)] enable you to use “==” operator,
  • You can import elements of enumeration using use keyword.

Homework: Try this example and remove first line: #[derive(PartialEq)]

Read next: Selection