[std] と [no_std]?
プログラムの先頭行にある #![no_std] 属性は、そのプログラムが標準ライブラリである std クレートを使用しないことを示します。代わりに、標準ライブラリのサブセットであり、基盤となるオペレーティングシステム(OS)に依存しない core ライブラリを使用します。これは完全にプラットフォームに依存せず、上流ライブラリ、システムライブラリ、libc を必要としません。これは、ロードされる最初のコードである環境では必要です。その結果、core ライブラリは std ライブラリで利用可能なすべての機能を提供するわけではありません。
コレクション
core ライブラリは Vec、String、HashMap を提供しません。これらは動的メモリアロケータ(ヒープ割り当て)を必要としますが、core はそれを提供しないためです。
他のクレートを使用しない場合、配列やタプルのような、コンパイル時にサイズが分かっている型に制限されます。
長さに関してもう少し柔軟に扱える別の型として、スライスがあります。スライスは、連続したメモリに格納された要素のリストへの参照です。スライスを作成する方法の 1 つは、連続したメモリに格納された固定サイズの要素リストである配列への参照を取ることです。
#![allow(unused)]
fn main() {
// スタックに割り当てられた配列
let array: [u8; 3] = [0, 1, 2];
let ref_to_array: &[u8; 3] = &array;
let slice: &[u8] = &array;
}
slice と ref_to_array は同じ方法で構築されますが、型は異なります。ref_to_array はメモリ上では単一のポインタ(32 ビットプラットフォームでは 1 ワード / 4 バイト)として表現されます。slice はポインタ + 長さ(32 ビットプラットフォームでは 2 ワード / 8 バイト)として表現されます。
スライスはコンパイル時ではなく実行時に長さを追跡するため、任意の長さのメモリ領域を参照できます。
#![allow(unused)]
fn main() {
let array1: [u8; 3] = [0, 1, 2];
let array2: [u8; 4] = [0, 1, 2, 3];
let mut slice: &[u8] = &array1;
log::info!("{:?}", slice); // length = 3
// ここで別の配列を指す
slice = &array2;
log::info!("{:?}", slice); // length = 4
}
この問題に対処する別の可能性:
heapless crate は、動的メモリ割り当てを必要とせず、固定された最大ストレージサイズを持つ、static に適したデータ構造を提供します。