Scalar types in Cairo (felt, integer, boolean, float)#
The Cairo compiler version used in this article is 2.0.0-rc0. Since Cairo is being rapidly updated, there may be slight differences in syntax between different versions, and the article content will be updated to the stable version in the future.
felt252#
felt252 is a basic type in Cairo, representing a storage slot. Literals without specified variable types default to felt252. felt252 can be a negative number or zero, and its range is:
-X < felt < X, where X = 2^{251} + 17* 2^{192} + 1
Any value within this range can be stored in felt252. Note: It is not -2^251 ~ (2^251 - 1)
.
felt252 can store both integers and strings. Here are examples of storing integers and strings:
use debug::PrintTrait;
fn main() {
// Using the let keyword to declare and assign a literal value, the default type should be felt252
let x: felt252 = 5;
let y: felt252 = 'ppppppppppppppppppppppppppp';
let z: felt252 = 'ppppppppppppppppppppppppppp99999999999999'; // Overflow
x.print();
}
Note: It is 252, not 256, and if you add other numbers after felt or leave it empty, it will result in a compilation error, for example,
felt256 felt
.
Short Strings#
Short strings are represented by single quotes and cannot exceed 31 characters in length. Short strings are essentially of felt252 type, but they are represented as strings, and computers convert characters to numbers using the ASCII protocol. The length of a short string cannot exceed the maximum value of felt252.
let mut my_first_initial = 'C';
Difference between felt252 and integers#
In Cairo 1.0, felt252 does not support division and modulo operations, while integers do.
Here is the description of felt in Cairo 0.1:
"Flet" is short for "field elements" and can be translated as "domain elements". The difference between felt252 and integers is mainly reflected in the division operation. When an operation that cannot be evenly divided occurs, such as 7/3, the result of integer division is usually 2, but not for felt252. felt252 always satisfies the equation x3 = 7. Since it can only be an integer, the value of x3 will be a huge integer that overflows, and the overflowed value happens to be 7.
In Cairo 1.0, division is prohibited for felt252.
use debug::PrintTrait;
fn main() {
let x = 7 / 3;
x.print();
}
// The above code will result in the following error
error: Trait has no implementation in context: core::traits::Div::<core::felt252>
--> f_felt252.cairo:4:13
let x = 7 / 3;
^***^
Error: failed to compile: src/f_felt252.cairo
Integers#
The core library includes these integer variables: u8, u16, u32 (usize), u64, u128, and u256
. They are all implemented using felt252 and come with integer overflow detection. When declaring an integer variable, if the variable type is not specified, it defaults to felt252. Here is an example:
let y = 2;
To specify u8, u16
, etc., the variable type needs to be indicated:
let x:u8 = 2;
The u256 type is more complex and requires the use of other types to construct it. In the core library, u256 is a struct with two fields, high and low, both of which are of type u128. Since a storage slot (felt252) cannot hold u256 data, it needs to be split into two storage slots for storage.
let z: u256 = u256 { high: 0, low: 10 }
This involves the concept of "high address segment" and "low address segment". If you are interested, you can search for related information.
Operators#
Integers support most operators and come with overflow detection. They support the following:
fn test_u8_operators() {
// Calculation
assert(1_u8 + 3_u8 == 4_u8, '1 + 3 == 4');
assert(3_u8 + 6_u8 == 9_u8, '3 + 6 == 9');
assert(3_u8 - 1_u8 == 2_u8, '3 - 1 == 2');
assert(1_u8 * 3_u8 == 3_u8, '1 * 3 == 3');
assert(2_u8 * 4_u8 == 8_u8, '2 * 4 == 8');
assert(19_u8 / 7_u8 == 2_u8, '19 / 7 == 2');
assert(19_u8 % 7_u8 == 5_u8, '19 % 7 == 5');
assert(231_u8 - 131_u8 == 100_u8, '231-131=100');
// Comparison
assert(1_u8 == 1_u8, '1 == 1');
assert(1_u8 != 2_u8, '1 != 2');
assert(1_u8 < 4_u8, '1 < 4');
assert(1_u8 <= 4_u8, '1 <= 4');
assert(5_u8 > 2_u8, '5 > 2');
assert(5_u8 >= 2_u8, '5 >= 2');
assert(!(3_u8 > 3_u8), '!(3 > 3)');
assert(3_u8 >= 3_u8, '3 >= 3');
}
Similarly, u256 also supports these operators:
use debug::PrintTrait;
fn main() {
let x:u256 = u256{high:3, low: 3};
let y:u256 = u256{high:3, low: 3};
let z = x + y;
assert(z == 2 * y, 'z == 2 * y');
assert(0 == x - y, '0 == x - y');
assert(1 == x / y, '0 == x - y');
assert(0 == x % y, '0 == x % y');
assert(x == y, 'x == y');
assert(x <= y, 'x <= y');
assert(x >= y, 'x <= y');
assert(x - 1 < y, 'x - 1 < y');
assert(x + 1 > y, 'x + 1 >= y');
assert(x != y - 1, 'x != y');
}
Boolean#
Boolean variables can be declared using the following syntax:
let is_morning:bool = true;
let is_evening:bool = false;
Float#
Not supported yet.