Skip to content
JA

Rust で科学計算機を作る — 変数と型を理解する

簡単な科学計算機を作りながら、Rust の変数と型を学びます。

19 min read

この学習 Rust シリーズへようこそ。ここでは記事ごとに 1 つのプロジェクトを構築して Rust を学習し、それぞれの概念をかなり深く学習します。これは私の新しい Rust シリーズであり、以前の Rust シリーズよりもはるかに包括的なものになります。最初の 5 ~ 6 記事では、プロジェクトは比較的単純ですが、その後は、大量の興味深いプロジェクトを構築し、多くのことを学ぶことになることを保証します。それでは、最初の記事から始めましょう

この記事では、簡単な関数電卓を構築することで、Rust の変数と型について学びます。

前提条件

どのプログラミング言語でも、少なくとも条件、変数、ループ、関数などの基本を知っている必要があります。 最も重要なことは、学ぶ意欲と努力をすることです。これは長くて厳しい旅になるでしょう、だからシートベルトを締めてください。

パート 1 - Rust のインストール

他の言語と同様に、使用する前にまずインストールする必要があるため、Rust のインストール手順に従って、Rustup を使用して Rust をインストール に戻ってください。

Rust をインストールした後、新しいターミナルを開き、コンパイラーが利用可能であることを確認します。

rustc --version

次のようなバージョンが表示されるはずです。

rustc 1.97.0

正確なバージョンは、Rust をいつインストールするかによって異なります。

次に貨物を確認します。

cargo --version

Cargo とは何ですか? と思われるかもしれません。Cargo は Rust のビルド システムおよびパッケージ マネージャーです。このシリーズ全体で Cargo を使用します。

Rustup を確認することもできます。

rustup --version

3 つのコマンドがすべて機能すれば、Rust のインストールの準備は完了です。

貨物の使用を開始する

Rust の学習を始める前に、このシリーズを通じて Rust プロジェクトをどのように作成、構築、実行するかを簡単に理解しましょう。

貨物とは何ですか?

Cargo は Rust のビルド システムおよびパッケージ マネージャーです。プロジェクトの作成、コードのコンパイル、プログラムの実行、コードのチェック、依存関係の管理などのタスクを処理します。

このシリーズでは Cargo を使用することになるので、基本的なコマンドに慣れておきましょう。

Rust プロジェクトの作成

最初の Rust プロジェクトを作成しましょう。

ターミナルを開き、プロジェクトを保存するフォルダーに移動して、次を実行します。

cargo new hello-rust

Cargo は、hello-rust という名前の新しいディレクトリを作成し、その中に基本的な Rust プロジェクトを含めます。

プロジェクトに移動します。

cd hello-rust

エディターでプロジェクトを開くと、次のような構造が表示されます。

hello-rust/
├── Cargo.toml
└── src/
    └── main.rs

これらのファイルが何であるかを理解しましょう。

Cargo.toml はプロジェクトのマニフェスト ファイルです。これには、名前、バージョン、Rust エディション、依存関係など、プロジェクトに関する情報が含まれます。

src/main.rs はバイナリ Rust アプリケーションのエントリ ポイントです。ここが main 関数が存在する場所です。

Cargo は、ビルド中に依存関係を解決した後、Cargo.lock ファイルも作成します。まだ心配する必要はありません。依存関係の管理については、このシリーズの後半で説明します。

プロジェクトの実行

src/main.rs を開きます。 Cargo は、小さな Hello World プログラムを生成します。

fn main() {
    println!("Hello, world!");
}

次のようにしてプログラムを実行できます。

cargo run

以下が表示されるはずです:

Hello, world!

cargo run は、必要に応じてまずプロジェクトをコンパイルし、次に結果の実行可能ファイルを実行します。

コードをチェックする

もう 1 つの便利なコマンドは次のとおりです。

cargo check

cargo check は、最終的な実行可能ファイルを生成せずにプロジェクトがコンパイルされるかどうかをチェックします。

完全なビルドを行わずにコードが有効かどうかをすぐに確認できるため、開発中に役立ちます。

このシリーズでは cargo check を頻繁に使用していることがわかります。

プロジェクトを構築する

プロジェクトをコンパイルするには、以下を使用できます。

cargo build

デフォルトでは、これによりデバッグ ビルドが作成されます。最終的に最適化されたリリース ビルドが必要な場合は、以下を使用できます。

cargo build --release

現時点では、デバッグ ビルドとリリース ビルドの違いを気にする必要はありません。それについては、必要になったらまたお話しします。

貨物ワークフロー

この時点で、覚えておく必要がある基本的なワークフローは次のとおりです。

cargo new       → create a new project
cargo check     → check that the code compiles
cargo run       → compile and run the program
cargo build     → compile the project

今のところ、Cargo に関する知識はこれで十分です。

Cargo、依存関係、ワークスペース、ビルド、プロジェクト構成については、このシリーズの後半で実際に必要になったときに学習します。

Rust プロジェクトを作成して実行する方法がわかったので、Rust 自体の学習を始めましょう。

変数

私たちが最初に学ぶことは、Rust の変数です。構文は他のプログラミング言語とよく似ていますが、最初から知っておくべき相違点がいくつかあります。

変数の作成

まずは変数の作成方法を学びましょう。

fn main() {
	let number = 10;
	
	println!("{number}")
}

ターミナルに次のように入力すると、これを実行できます。

cargo run

出力 10 が表示されるはずです。 let number = 10; 行は変数バインディングを作成します。次の画像でお見せしましょう。

画像1

Rust の用語では、let を名前と値の間に バインディング を作成するものと考えると便利です。ここでは基本的に、名前 number が値 10 を参照することを Rust に伝えています。今はタイプについて心配する必要はありません。すぐに説明します。

これは JavaScript や Python などの言語に非常によく似ていると思われるかもしれませんが、では、私が話した違いは何でしょうか。バインディングに関連する情報とは何なのかを説明してみましょう。 画像2 現時点では、バインディングには number という名前があり、値 10 を参照しており、値には型があり、バインディングはデフォルトで不変であり、バインディングは特定のスコープ内に存在することに注意する必要があります。これらのプロパティについては、このセクションの後半と次のセクションで再度説明します。

変数はデフォルトでは不変です

このプログラムを実行してみましょう:

fn main() {
    let number = 10;

    number = 20;

    println!("{number}");
}

不変変数に代入できないというエラーが表示されます。

これを覚えておく必要があります: let で作成されたバインディングはデフォルトでは不変です

バインディングに関連付けられた値を変更したい場合は、それが変更可能であることを明示的に示す必要があり、キーワード mut を使用してそれを行います。

fn main() {
    let mut number = 10;

    number = 20;

    println!("{number}");
}

cargo run を使用してプログラムを実行すると、出力 20 が表示されます。

現時点では、その区別だけで十分です。所有権と借用権により、この区別はシリーズの後半でさらに重要になります。

再割り当て

このプログラムを実行してみましょう。

fn main() {
	let mut number = 10l;
	
	number = 20;
	number = 30;
	
	println!("{number}")
}

出力 30 が得られます。最初にバインディング number を値 10 で作成し、次に 20 に再割り当てし、さらに 30 に再割り当てして、最後に number を出力します。

シャドーイング

Rust では、次のように同じ名前を使用して別のバインディングを宣言できます。

fn main() {
	let number = 10;
	let number = 20;
	
	println!("{number}")
}

ここで、実行して出力を確認すると、出力 20 が得られます。最初は、これは再割り当てのように見えるかもしれませんが、そうではありません。これを shadowing と呼びます。再割り当てとシャドウイングには微妙な違いがあります。シャドウイングでは、2 番目の let が前のバインディングと同じ名前を持つ新しいバインディングを作成することがわかります。再割り当てでは、同じ名前を持つ複数のバインディングは作成しません。

シャドウイングによってタイプも変更される場合があります。

fn main() {
	let value = 10;
	let value = "ten";
	
	println!("{value}")
}

これを実行すると、出力が ten になることがわかります。再割り当てを使用してこれを実行すると、失敗し、エラーが表示されます。

fn main() {
	let mut value = 10;
	value = "ten";
	
	println!("{value}")
}

このシャドーイングの概念はこのシリーズの後半で使用するため、今のところはこの概念をここに残しておき、さらに詳しく学ぶために後の記事で取り上げます。

範囲

これらのバインディングにもスコープがあります。スコープとは、バインディングを使用できるプログラムの領域です。例を挙げて説明しましょう。

fn main() {
	let outer = 10;
	
	{
		let inner = 20;
		println!("{outer}")
		println!("{inner}")
	}
	
	println!("{outer}")
}

このような範囲は他の言語でも見たことがあると思います。内部バインディング スコープはネストされたブロック内にのみ存在し、外部バインディング スコープはプログラムの最後まで存在します。したがって、プログラムを実行するときに、プログラムがネストされたブロックから出ると、inner バインディングは使用できなくなります。そのため、そのネストされたブロックの外側で inner バインディング値を出力しようとすると、エラーが発生します。上記のコードの範囲を次のビジュアルで示します。 画像3 後でスコープの概念を理解し、所有権と有効期間と結び付けますが、今のところは、スコープとはバインディングが利用可能な領域であることだけを理解してください。

値は実際にどこに存在するのでしょうか?

Rust プログラムで let number = 10; を記述すると実際に何が起こるのか疑問に思われるかもしれません。今は簡単に説明できますが、これについては後の記事で詳しく説明します。

したがって、整数などの単純な値の場合、コンパイラは一般に、生成されたコードがどのように最適化および使用されるかに応じて、マシンのストレージ、多くの場合レジスタまたはスタック メモリで値を直接表すことができます。

変数は常にスタック上に存在するとは限りません。非常に単純化しているので、上記の簡単な説明を少し理解してください。先ほども言いましたが、これについては別の記事で詳しく説明しますので、今のところはマシン レベルの詳細には焦点を当てず、言語レベルの動作を学習することに集中していただければ幸いです。

最後の実験

学んだことをこのプログラムと組み合わせてみましょう。

fn main() {
	let number = 10;
	
	{
		let mut number = number;
		
		number = 20;
		
		println!("{number}");
	}
	
	println!("{number}")
}

プログラムを実行して出力を確認する前に、まず出力を推測してみてください。まず、外部バインディング number を作成し、値は 10 です。次に、ネストされたブロック内に同じ名前の内部バインディングを作成しました。これにより、外部の number バインディングがシャドウされ、この内部バインディングの値は 10 となり、値を再割り当てしています。 20(内部バインディングに mut があるためこれが可能です)、number を印刷すると 20 が得られます。最後に、ネストされたブロックの外に存在し、number を再度出力しますが、今回は外側の number バインディングを指すため、値 10 を出力します。

ここまでで、基本的な変数モデルに慣れてきたはずだと思います。さて、型に入ることができます

タイプ

他の言語と同様に、Rust にも型があります。最初に使用したのと同じ例を使用して、値自体を見てみましょう。

let number = 10;

number10 を参照していることはわかっていますが、問題は 10 の場合はどのような値ですか? これがセクションの残りの部分で焦点を当て、Rust が提供するすべての一般的な型を理解することになります。

一般に、型は、どのような種類の値を処理しているのか、またその値に対してどのような操作が有効であるのかを示します。

非常に基本的な例から始めましょう。

fn main() {
	let number = 10;
	
	println!("{number}")
}

実行すると、出力 10 が表示されます。私たちはすでにこのことを知っており、何も驚くべきことではありません。次に、その型を明示的にしましょう。

fn main() {
	let number: i32 = 10;
	
	println!("{number}")
}

これにより、再び 10 が出力されますが、このプログラムでは、値が持つべき型を明示的に示しました。

値の型を明示的に指定するために使用する構文は次のとおりです。

let name: Type = value;

基本的な例では、number はバインディング名、i32 はタイプ、10 は値です。

型は実際に何を決定するのでしょうか?

型は、どのような値を表現できるか、それらの値に対する操作がどのように動作するか、どの操作が有効であるか、値が他の値とどのように相互作用できるか、実行時にコンパイラが値をどのように表現するかなどを決定します。これらは、知っておくべき最も一般的なことだと思います。 たとえば、整数は算術演算をサポートします。

fn main() {
	let a: i32 = 10;
	let b: i32 = 20;
	
	let result = a + b;
	
	println!("{result}");
}

i32 が加算をサポートしているため、これが機能します。しかし、Rust では、無関係な型の任意の値を組み合わせることができません。たとえば:

fn main() {
	let a: i32 = 10;
	let b: f64 = 20.5;
	
	let result = a + b;
	
	println!("result")
}

これを実行すると失敗します。Rust は 2 つの異なる型 i32f64 を認識し、コンパイラは両方が同じ型ではないため操作を実行できないと警告するからです。この操作を実行するために型を変換する方法については後で説明しますが、ここでは、異なる型に対して操作を実行すると Rust では失敗することを覚えておいてください。

Rustのスカラー型

Rust には、いくつかのプリミティブなスカラー型があります。 4 つの主なカテゴリは次のとおりです。

スカラー型
整数
浮動小数点数
ブール値
キャラクター

整数および浮動小数点のカテゴリには、複数の具象型が含まれます。これらのタイプをそれぞれ見て、それぞれのタイプについて 1 つずつもう少し詳しく理解しましょう。

符号付き整数

符号付き整数は、正と負の両方の整数を表すことができます。 Rust には符号付き整数のバリエーションがいくつかあり、これらのバリエーションは整数のサイズをビット単位で表します。

符号付き整数
i8
i16
i32
i64
i128
isize

プログラムでは異なる数値範囲が必要になる場合があるため、符号付き整数にはさまざまなバリエーションがあります。たとえば、i8 は 8 ビットで -128 through 127 を表現できますが、i32 は 32 ビットで -2,147,483,648 through 2,147,483,647i64 はさらに多くのビットを表現できます。ご理解いただけると幸いです。

符号なし整数

符号なし整数 (はい、ご想像のとおり) は負の値を表すことができません。たとえば:

fn main() {
	let count: u32 = 100;
	
	println!("{count}");
}

これはまったく問題なく機能しますが、100 を次のように負の数値に置き換えると次のようになります。

fn main() {
	let count: u32 = -100;
	
	println!("{count}")
}

ここで、これを実行しようとすると、u8 の範囲が 0 through 255 であり、負の数値が無効であるため、コンパイラはエラーを出します。

usize および isize

特に注意していただきたい整数型は usizeisize の 2 つです。 i32u64 とは異なり、そのサイズはターゲット アーキテクチャによって異なります。たとえば、64 ビット システムでは、usize は 64 ビット、isize は 64 ビットですが、32 ビット システムでは、usize は 32 ビット、isize は 32 ビットです。 usize は、サイズとインデックスを操作するときに非常に一般的に使用されます。後でコレクションを扱うときに ti が頻繁に登場します。 usize の使用法については後の記事で説明しますが、ここでは要点だけを理解していただきたいと思います。

浮動小数点型

私たちはミニ関数電卓を構築しているので、明らかに 10 進数値のサポートと、Rust が提供する 2 つの浮動小数点型 f32f64 をサポートする必要があります。 浮動小数点の基本的な例も示します。

fn main() {
	let a: f32 = 10.5;
	let b: f64 = 20.5;
	
	println!("{a}");
	println!("{b}");
}

ブール値

Rust はブール型もサポートしており、bool で表されます。取り得る値は、truefalse の 2 つだけです。基本的な例を示します。

fn main() {
	let is_running: bool = true;
	let is_finished: bool = false;
	
	println!("{is_running}");
	println!("{is_finished}");
}

キャラクター

Rust は文字型と char キーワードで表される文字型もサポートしています。 char は、単一の Unicode スカラー値を表します。たとえば:

fn main() {
	let letter: char = 'R';
	let symbol: char = '😀';
	
	println!("{letter}");
	println!("{symbol}");
}

文字を定義するときは一重引用符を使用していることに注意してください。二重引用符を使用すると、文字列リテラルになります。この2つはタイプが違います。

したがって、上記の例から、Rust char は Unicode スカラー値を表現できることがわかります。これが、char を「1 バイト」と考えるべきではない理由です。 Rust の char は、Unicode スカラー値を表す 4 バイトの型です。

型推論

当初は変数の型を記述していませんでしたが、最近では変数の型について明示的に言及するようになりました。つまり、Rust ではすべての変数に注釈を付ける必要はなく、Rust が型を推論します。これは 型推論 と呼ばれます。 型推論は、変数に型がないことを意味するものではありません。その変数にはコンパイル時の具体的な型がまだあります。 Rust が単にそのタイプを決定しただけです。この理論を例で検証することもできます。

fn main() {
	let number = 10;
	
	println!("{}", std::any::type_name_of_val(&number));
}

出力は i32 として表示されるはずです。

数値リテラルの接尾辞

Rust では、数値リテラルに型サフィックスを付けることができます。これは、型を明示的にするもう 1 つの方法です。

fn main() {
	let a = 10_i32;
	let b = 10_i64;
	let c = 10.5_f64;
}

サフィックスは、リテラルがどのような型を持つべきかを Rust に指示します。したがって、10_i64 は、整数リテラル 10 の型が i64 である必要があることを意味します。私たちが学んだ最初の方法ではバインディングに型アノテーションを使用し、この方法ではリテラルに型サフィックスを使用します。

Rust は暗黙的に数値型を変換しません

前に使用した例に戻りましょう。

fn main() {
	let a: i32 = 10;
	let b: f64 = 20.5;
	
	let result = a + b;
	
	println!("{result}");
}

これを実行すると、2 つの異なるタイプで操作を実行しようとしているため、失敗します。正常に実行するには、次の 2 つの型のいずれかを変換し、両方の型を同じにする必要があります。

fn main() {
	let a: i32 = 10;
	let b: f64 = 20.5;
	
	let result = a as f64 + b;
	
	println!("{result}");
}

その as f64 を使用して、整数 af64 に変換し、操作を実行できるようになりました。型変換については、このシリーズの後半でさらに詳しく学習します。

関数電卓を構築する

これから、計算機を段階的に構築していきます。すでに Rust をインストールしていることを願っていますが、まだインストールしていない場合は、この記事の先頭に移動して Rust のインストール リンクを取得し、指示に従ってください。完了したら、戻ってこのプロジェクトの作業を開始してください。

プロジェクトを作成する

ターミナルを開いて、このプロジェクトを作成したいフォルダーに移動して、新しい Cargo プロジェクトを作成してみましょう。

cargo new scientific-calculator

次に、このプロジェクトを好みの IDE で開きます。 Zed IDE を使用します プロジェクトを開くと、次のフォルダー構造が表示されます。

scientific-calculator/
├── Cargo.toml
└── src/
    └── main.rs

このプロジェクトでは、Rust の標準ライブラリのみを使用するため、Cargo.toml を変更する必要はありません。

src/main.rs を開くと、Cargo によって生成された hello world プログラムがあることがわかります。それを置き換えて Scientific Calculator を出力しましょう。

fn main() {
	println!("Scientific Calculator");
}

cargo run で実行すると、端末に Scientific Calculator が表示されるはずです。

4 つの基本操作を追加する

4 つの基本的な算術演算をすべて追加してみましょう。

fn main() {
    let a: f64 = 20.0;
    let b: f64 = 6.0;

    let addition = a + b;
    let subtraction = a - b;
    let multiplication = a * b;
    let division = a / b;

    println!("Addition: {addition}");
    println!("Subtraction: {subtraction}");
    println!("Multiplication: {multiplication}");
    println!("Division: {division}");
}

これを実行すると、すべての操作は正常に動作していますが、除算の書式設定が欠落していることがわかります。それについては後で対処します。

最初の科学的作戦を追加

平方根、べき乗、三角関数の演算を追加しましょう。

fn main() {
    let a: f64 = 20.0;
    let b: f64 = 6.0;

    let addition = a + b;
    let subtraction = a - b;
    let multiplication = a * b;
    let division = a / b;

    let square_root = 25.0_f64.sqrt();
    let power = 2.0_f64.powi(8);
    let sine = 0.0_f64.sin();
    let cosine = 0.0_f64.cos();

    println!("Addition: {addition}");
    println!("Subtraction: {subtraction}");
    println!("Multiplication: {multiplication}");
    println!("Division: {division}");
    println!("Square root: {square_root}");
    println!("Power: {power}");
    println!("Sine: {sine}");
    println!("Cosine: {cosine}");
}

これで、見た目は少し良くなりましたが、まだ問題が 1 つあります。入力がハードコーディングされているため、ユーザーから入力を取得する方法が必要です。次はそれに取り組みましょう。

コマンドライン引数の読み取り

ユーザー入力を読み取るために、コマンドライン引数を読み取ることができます。Rust は、プログラムに渡される引数にアクセスするための std::env::args を提供します。今のところは、数値の解析や計算の実行について心配する必要はありません。まず、コマンドラインを介して引数から何を受け取るかを見てみましょう。 完全な main.rs コードをコメント アウトして、次のコードを記述します。

fn main() {
	let args = std::env::args();

    println!("{:?}", args);
}

今すぐ実行してください:

cargo run -- add 10 20

プログラムに渡された引数を表す出力が表示されるはずです。ただし、args はイテレータであり、これを直接出力することは、今回の目的には特に役立ちません。引数をベクトルに集めてみましょう。

イテレータやベクトルなどが理解できなくても心配する必要はありません。これらについては後で学びます。ここでは、ユーザー入力を取得するためにそれらを使用しているだけです。この記事の主な目的は変数と型について理解することであり、それはこの時点ですでに完了しています。

fn main() {
    let args: Vec<String> = std::env::args().collect();

    println!("{args:?}");
}

実行:

cargo run -- add 10 20

次のようなものが表示されるはずです。

["target/debug/scientific-calculator", "add", "10", "20"]

正確な最初の値は環境によって異なります。

重要な部分は次のとおりです。

"add"
"10"
"20"

これらは私たちが提供した引数です。

-- があるのはなぜですか?

次のようにプログラムを実行していることに気づいたかもしれません。

cargo run -- add 10 20

-- は、Cargo の引数をプログラムの引数から分離します。 -- より前のすべてが Cargo によって解釈されます。 -- 以降はすべてプログラムに渡されます。

それで:

cargo run -- add 10 20

意味:

Cargo
  |
  └── run the program
          |
          ├── "add"
          ├── "10"
          └── "20"

個々の引数へのアクセス

インデックスを使用して、収集された引数の個々の要素にアクセスできます。

プログラムを次のように変更します。

fn main() {
    let args: Vec<String> = std::env::args().collect();

    println!("Operation: {}", args[1]);
    println!("First value: {}", args[2]);
    println!("Second value: {}", args[3]);
}

実行:

cargo run -- add 10 20

次のものを取得できるはずです:

Operation: add
First value: 10
Second value: 20

なぜ args[0] ではなく args[1] から始めるのでしょうか?最初の引数 args[0] はプログラムの実行可能ファイル名またはパスであるためです。

画像5

数値の解析

ユーザーが実行したい操作と値を取得することはできますが、問題は値がコマンドラインから文字列として取得されることです。数学的な操作を実行するには値を数値に変換する必要があります。解析するには、次のようなことができます。

fn main() {
    let args: Vec<String> = std::env::args().collect();

    let a = args[2].parse::<f64>().unwrap();
    let b = args[3].parse::<f64>().unwrap();

    let result = a + b;

    println!("{result}");
}

実行すると、出力として 30 が表示されるはずです。ここで必要な残りの作業は、以前にコメントアウトした操作を元に戻し、条件を使用して実行する操作を選択することです。

操作の選択

ここまでは、ユーザーが実行したい操作と浮動小数点型の値を取得することができました。 Rust で条件文を使用します。今は条件について深く掘り下げるつもりはありませんが、このプロジェクトでは基本的な if-else ブロックを使用するので、心配する必要はありません。

fn main() {
    let args: Vec<String> = std::env::args().collect();

    let operation = &args[1];

    if operation == "add" {
        let a = args[2].parse::<f64>().unwrap();
        let b = args[3].parse::<f64>().unwrap();

        println!("{}", a + b);
    } else if operation == "subtract" {
        let a = args[2].parse::<f64>().unwrap();
        let b = args[3].parse::<f64>().unwrap();

        println!("{}", a - b);
    } else if operation == "multiply" {
        let a = args[2].parse::<f64>().unwrap();
        let b = args[3].parse::<f64>().unwrap();

        println!("{}", a * b);
    } else if operation == "divide" {
        let a = args[2].parse::<f64>().unwrap();
        let b = args[3].parse::<f64>().unwrap();

        println!("{}", a / b);
    } else if operation == "sqrt" {
        let value = args[2].parse::<f64>().unwrap();

        println!("{}", value.sqrt());
    } else if operation == "pow" {
	    let base = args[2].parse::<f64>().unwrap();
	    let exponent = args[3].parse::<i32>().unwrap();
	
	    println!("{}", base.powi(exponent));
    } else if operation == "sin" {
        let value = args[2].parse::<f64>().unwrap();

        println!("{}", value.sin());
    } else if operation == "cos" {
        let value = args[2].parse::<f64>().unwrap();

        println!("{}", value.cos());
    } else {
        println!("Unknown operation: {operation}");
    }
}

これはコード行数が多いように見えますが、大量の if-else ブロックを使用しているだけです。それだけです。他の言語とよく似ているので、特に説明はしません。しかし要約すると、ユーザーが実行したい操作を受け取り、その後、一連の if-else ブロックを使用してどのブロックが操作を満たすかを確認し、そのブロックでコマンド ラインから値を読み取り、操作を実行して結果を出力します。

各ブロック内の値を読み取るので、どの演算に必要な値がいくつ必要かを簡単に判断できます。たとえば、平方根には値が 1 つだけ必要ですが、加算には 2 つの値が必要です。

次に、それらをテストします。

cargo run -- sqrt 25
5
cargo run -- sin 0
0
cargo run -- cos 0
1

さあ、Rust でミニ関数電卓の構築が完了しました。さらに実験したい場合は、自分で操作をさらにいくつか追加してみてください。 tanlog、またはその他便利だと思われるものを追加できます。

そして、あなたがこれに従って電卓を自分で構築したり、興味深い変更を加えたりする場合は、自由に X にタグ付けしてください。私はあなたが構築したものを見てみたいと思っており、このシリーズをフォローしていただいたことへのささやかな感謝のしるしとして、そのほとんどを再投稿します。

次の記事では、数字推測ゲームを構築することによって、Rust の制御フローについて学びます。次回でお会いしましょう。

Navigation

Type to search…

↑↓ navigate↵ selectEsc close