「C・C++からRubyへ」を読む
多すぎる。気になったところだけピックアップする。
情報源
C/C++との違い
Cとの類似
- Rubyには
++
と--
がない const
のような特別なキーワードがないri
がman
の代わり
C++との類似
Cとの違い
- コンパイル、メイク、リンク不要。アセンブリコードに変換できない
- 色々ない。ヘッダファイル、マクロ、プリプロセッサ(
#define
等)、キャスト、ポインタ、typedef
、sizeof
がない - メモリ操作不要(GCまかせ)
- メソッドの引数は値渡し。参照渡しでない
#include "foo"
でなくrequire 'foo'
- 行末セミコロン不要
- 括弧不要
char
型はない- すべて式
C++との違い
- 明示的に参照を扱うことはない
- 強い型付けがされますが、それは動的に行われます
- コンストラクタはクラス名ではなく
initialize
メソッド - 外部からメンバ変数に直接アクセスすることはない
- 多重継承はない。代わりにMix-inを使う
- いつでもクラスを変更できる
- イテレータはない。代わりに
each
などのイテレータメソッドを使う - コンテナクラスは
Array
とHash
だけ - ユニットテストのライブラリはRubyに標準添付されています
やってみる
気になったものをいくつかピックアップしてirb
で確かめてみる。
<<
はリストに要素を追加する
> a = [] => [] > a << 1 => [1] > a << 3 => [1, 3] > a << 5 => [1, 3, 5]
いいね! ビットシフト演算子なんてそんなに使わないし、これでいいよ。
Rubyのmodule
はC++のnamespace
です
module MyMod class MyClass def my_method; puts 'あはは'; end end end MyMod.MyClass.new.my_method
(irb):45:in `<main>': undefined method `MyClass' for MyMod:Module (NoMethodError) Did you mean? class
は? 怒られたんですけど。
MyMod::MyClass.new.my_method
ああそういうこと。.
でなく::
なのね。モジュールのときは子参照に::
を使えと。たしかC++ではクラスメソッドを参照するときに::
を使っていたような気がする。Rubyではモジュールのとき::
を使うのね。めんどくせ。.
で統一すればいいじゃん。2文字なのもいただけない。長いよ。
例外の作法は一緒ですがキーワードが違います
そのキーワードとやらを教えて欲しかった。ググったところ以下だった。
begin raise # エラーを発生させます。 rescue => e p e #=> RuntimeError ensure p "絶対実行" end
うわぁ、begin
とか。嫌だなぁ。なんかBASIC言語みたいでモッサリ感ただようというか。レガシー臭というか加齢臭というか。時代においていかれた古代の遺物的な。骨董品的な。あまりに汎用性が高すぎて{}
以上の意味がパッと見でわからない。begin
というキーワードをみると、何かをおっぱじめるつもりなのはわかるが、それ以外なにもわからないから不安になる。最初に目に入る語としてどうなの。字数も多い。
また新しい英語を覚えなきゃいけないじゃん。try
-catch
-finally
にしてほしかったわ。
英語 | カタカナ | 意味 | 他言語 |
---|---|---|---|
begin |
ビギン | 始める | try |
end |
エンド | 終わる | (なし) |
rescue |
レスキュー | 救助する | catch ,except |
raise |
レイズ | (上に高く)持ち上げる | throw |
ensure |
インシュア | 保証する | finally |
rescue
とensure
が見慣れない。
はたして読みからスペルを再現できるのか。rescue
とensure
は書いて覚えなきゃならん。でもensure
は書く機会が少なそう。begin
は一時期、非同期処理とかで書いていたので覚えたが。
raise
はPythonと同じなのでいい。
=> e
ってやつがキモチワルイ。アロー演算子は使わないし、無名関数はProc
なRubyが、ここにきて=>
とかいう謎記号を使ってくるとか。いやもうrescue e
とかでいいだろ。せめてrescue (e)
とかさぁ。メソッド呼出でさえ()
省略できるのに……。なぜここにきて=>
なんぞが必要になるの? なぜヘンな記号を使おうとするの? そんなことするんだったらbegin
,end
を{}
にしてくれよ。いらないところで無駄に記号を使うのがカッコいいとか思ってない? やめて。
今までRuby書いててすごく気持ちよかったけど、この例外処理だけは最悪。Pythonのtry
,except
,else
,finally
,raise
のほうがずっとわかりやすいし、短く書ける。例外処理は大事なだけに痛い。
#include "foo"
でなくrequire 'foo'
require
で外部ファイルを取り込む。対象ファイルはライブラリ(.dll
,.so
)やrbスクリプト。
コードを用意する。
lib.rb
def method; puts 'これはlib.rbにあるmethodメソッドです。'; end
main.rb
#!/usr/bin/env ruby require './lib.rb' method
実行する。
chmod +x main.rb ./main.rb
OK! ちゃんと別ファイルのメソッドが参照された。
これはlib.rbにあるmethodメソッドです。
インポート系って言語によって全然違うよね。超ややこしいんだよ。
キーワード | 意味 | 言語 |
---|---|---|
#include |
含める | C/C++ |
import |
輸入する | Python, JavaScript, Java |
using |
を使用して | C# |
use |
使う | Rust |
require |
必須 | Ruby, Node.js |
意味的にはimport
がわかりやすいけれど、PythonやJavaScriptのそれは使い方が難しいので嫌い。単語としてはuse
が一番シンプルで短い。さすが後発言語。スマートだね。まあCargo.tomlとあわせて使わなきゃいけなかったりするけど。
それにひきかえrequire
って。長いし単語が難しい。あと必須って意味なのもひっかかる。でも相対パスで使えるのはいいね。Pythonはそこんところクソだから。組込のファイル名と重複して使えないことが稀によくある。Rubyはそんなことがなさそうで安心した。使いやすそう。
コンストラクタはクラス名ではなくinitialize
メソッド
class C def initialize; puts '初期化'; end end
> C.new
初期化
finalize
はないの? ググったけど超古い情報しかなかった。
- DestructorはないけどFinalizerはあった件
- Ruby 1.8.7 finalize
- Ruby 1.8.7 define_finalizer
- Ruby latest define_finalizer
class C def initialize ObjectSpace.define_finalizer(self, C.finalize) end def C.finalize proc { puts "bar" } end end C.new
- クラスメソッドにしないとダメ。
self
が参照されつづけて解放されなくなるから Proc
を返さないとダメ
これは面倒すぎる。とくにproc
で書かないとダメなのがウザい。ネストが深くなる。
多重継承はない。代わりにMix-inを使う
Mix-inってなに。ググったら以下がわかりやすかった。
module Mod def method; puts 'モジュールのメソッドです。'; end end class X; include Mod; end
> X.new.method
モジュールのメソッドです。
今回はとりあえずこれだけ知っていればいいかな。
気になったのはモジュールの使い方。これってそんなに使うのかな? クラス間をまたぐ共通メソッドなんかを定義するときに使いそうだが。まあ1つしかできない継承だけでは厳しいし。そのときになったらまた考えよう。
ユニットテストのライブラリはRubyに標準添付されています
情報がないのでググった。
標準ライブラリを使って単体テストをしてみる。まずは適当にコードを書く。
lib.rb
def get_name 'ytyaru' end
次に上記をテストするコードを書く。
test_lib.rb
#!/usr/bin/env ruby require './lib.rb' require 'test/unit' class TestLib < Test::Unit::TestCase class << self def startup; p :_startup; end def shutdown; p :_shutdown; end end def setup; p :setup; end def teardown; p :teardown; end def cleanup; p :cleanup; end def test_get_name assert_equal('ytyaru', get_name) end def test_get_age assert_equal(100, get_name) end end
なお、assert_
系メソッドは以下のInstance Method Summary
項に一覧がある。
テストを実行する。
chmod +x test_lib.rb ./test_lib.rb
結果は以下。
Loaded suite ./test_lib Started :_startup :setup :cleanup :teardown .:_shutdown Finished in 0.005678889 seconds. --------------------------------------------------------------------------------------------------------------------------------------- 1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed --------------------------------------------------------------------------------------------------------------------------------------- 176.09 tests/s, 176.09 assertions/s
ほかにも便利な記述がたくさんある。詳細は以下参照。
くわしくはまた必要になったら勉強しよう。今は触りだけサクッとやるだけに留める。
後日以下にコードを書いた。
所感
なんか、Rubyの情報って古いのばっかりヒットするんですけど。2015〜2018年くらいな感じ。だいぶ下火なのかな。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
$ uname -a Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux