RubyのエンジニアはRustの最初に困ったこと
- 気持ち: 他の言語とくらべると、考えりが違います。
- いくつか新しい言葉がありますので、困ります。 (mut, ownership, trait, )
- 最初に簡単な関数を書きましたが、ビルドでエラーは良く発生しました。
現在
- ユニークビジョン株式会社ではRubyをRustに変えています。
- 心理的にRubyをRustに簡単に変えるように説明します。
Class/def VS Struct / impl
Rubyでは
- Class / def
- データを持つ
- 処理を定義する
class User
def initialize(id, name, addr)
@id = id
@name = name
@addr = addr
end
def hello
puts "hello #{@name}"
end
end
user1 = User.new(1, 'hoge', 'aaaaaa')
user1.hello()
Rustでは
- Classがありません
- データもつはStructを使います
- 処理はStructにimplを使います
struct User {
id: u64,
name: String,
addr: String,
}
impl User {
fn hello(&self) {
println!("Hello {}", self.name);
}
}
fn main() {
let user1 = User {
id: 1,
name: String::from("hoge"),
addr: String::from("aaaaaa"),
};
user1.hello()
}
Module vs Trait
RubyのModule
- 処理は別で定義出来ます
module Cream
def cream
puts "Hello Qiita User"
end
end
class Cookie
include Cream
end
cookie = Cookie.new
cookie.cream
RustのTrait
- 処理も別で定義出来ます
trait Cream {
fn cream(&self) {
println!("Hello Qiita User");
}
}
struct Cookie { }
impl Cream for Cookie { }
fn main() {
let cookie = Cookie { };
cookie.cream()
}
他の言語と似てるものは
- abstract class
- interface
変数/Type
Rubyでは
- 変数のTypeは明確の定義ががありません。
a = 1
puts a.class
a = "helo"
puts a.class
結果
Integer
String
Rustでは
- 変数の値のデフォルトは変更不可
- 変数の型は固定
- Mut / OwnerShipの概念があり: https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
fn print_type_of<T>(_: T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let a = "aa";
a = "bb"
}
error[E0384]: cannot assign twice to immutable variable a
fn main() {
let mut a = "aa";
a = 1
}
error[E0308]: mismatched types
つまり
- Rustはメモリー管理は厳しいので、変数と型の定義も厳しいです。
- 慣れるだけじゃなく、新しい変数を使うときに、この変数は必要かどうかをちゃんと考えないといけません。
Result/Error の考えり
Rubyでは
- ロジックを集中にして、動作確認して、そのあとにエラーハンドリングをやります。
処理開発
GaibuAPI1::execute()
GaibuAPI2::execute()
GaibuAPI3::execute()
GaibuAPI4::execute()
-
動作確認
-
エラーハンドリング
begin
GaibuAPI1::execute()
GaibuAPI2::execute()
GaibuAPI3::execute()
GaibuAPI4::execute()
rescue GaibuAPI1Error => exception
# TOTO
rescue GaibuAPI2Error => exception
# TOTO
rescue GaibuAPI3Error => exception
# TOTO
rescue GaibuAPI4Error => exception
# TOTO
ensure
# TODO
end
Rustでは
- 関数の結果は結果とエラーをResultに返します。https://doc.rust-lang.org/std/error/trait.Error.html
- 処理を書くときに、エラーのハンドリングを定義しないとコンパイラーエラーが発生しますので、同時に考えないといけません。
use std::fs::File;
fn main() {
let f: u32 = File::open("hello.txt");
}
Compiling error-handling v0.1.0 (file:///projects/error-handling)
error[E0308]: mismatched types
--> src/main.rs:4:18
|
4 | let f: u32 = File::open("hello.txt");
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found enum `Result`
| |
| expected due to this
|
= note: expected type `u32`
found enum `Result<File, std::io::Error>`
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}
ライブラリーに対すす
Ruby
- https://rubygems.org/
- Gem / Bundle
Rust
コード実行
Ruby
- rubyインストールしたら、コードを実行できます。
- サーバーで動くために、rubyコードがないといけません
- PHP / Javascriptと同じ
Rust
- rustインストール必要
- コード直接に実行できず、コードをビルドしないといけません
- サーバーで動くのはrustコードが必要じゃなく、ビルドしたファイルだけで十分です。
最後に
- rustを書くときに、rubyと似てるものはあります。
- rubyの考えり方でそのまま持ってRustに行かないで、考えりを少し変えないといけません。