削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎ユーザー定義クラス: Ruby#ユーザー定義クラスの都市間の大圏距離を求めるメソッドを追加した例を、Crystalに移植しました。
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎Ruby との違い: <ref>[https://crystal-lang.org/reference/1.5/syntax_and_semantics/macros/ Macros - Crystal]</ref>→‎BigInt
タグ: 2017年版ソースエディター
53 行
Crystalは、Rubyに触発された構文を持つものの、Rubyとの互換性をゴールに定めては'''いません'''。
このため、細部を見ると仕様に差異があり、Rubyのソースコードをcrystalに掛けるても前節の 'Hello World' の様にコンパイルに失敗することがあります。
また、コンパイルできても実行結果に違いが出ることがあます。
 
ここでは、Ruby との違いについて実際のコードと双方の結果を比較することで、差異についての理解を深めていきます。
79 行
: Ruby の整数は、桁あふれが起こると自動的に多倍長整数に型変換されるので、継ぎ目なしに大きな数を扱うアルゴルズムが使えます。
: Crystal の整数は、固定長です(大きさについては[[#リテラルと型|後述]])。なので大きな答えになる式を評価すると桁あふれが生じます。桁あふれが生じますが、C言語のように寡黙に処理を続けるのではなく、実行時に例外(OverflowError)が上がるので、例外を捕捉し然るべき処置を施すことが可能です。
 
==== BigInt ====
<code>big</code> を <code>require</code> すると <code>BigInt</code> が使えるようになります。
;BigInt:<syntaxhighlight lang=Crystal>
require "big"
 
p BigInt.new(2) ** 999
p (BigInt.new(2) ** 999).class
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="console">
5357543035931336604742125245300009052807024058527668037218751941851755255624680612465991894078479290637973364587765734125935726428461570217992288787349287401967283887412115492710537302531185570938977091076523237491790970633699383779582771973038531457285598238843271083830214915826312193418602834034688
BigInt
</syntaxhighlight>
: BigIntはプリミティブではなので、リテラル表現はありません。また、
::<syntaxhighlight lang=Crystal>
n : BigInt = 2
</syntaxhighlight>
::<syntaxhighlight lang=console>
Error: type must be BigInt, not Int32
</syntaxhighlight>
:: のように型アノテーションすることも出来ません。
 
=== リテラルと型 ===
111 ⟶ 132行目:
 
;サイズを指定した数リテラル:<syntaxhighlight lang=Crystal>
[1_i64, 2_u32, 3_u64, 4_i32, 5_i16, 6_u8, 7_i128, 8_u128, 3.14_f32, 1.44_f64].each{|x|
p [x, x.class]
}
123 ⟶ 144行目:
[5, Int16]
[6, UInt8]
[7, Int128]
[8, UInt128]
[3.14, Float32]
[1.44, Float64]
</syntaxhighlight>
: Crystal では、数値リテラルに _ で始まるサーフィックスを付け { i:符号付き整数, u:符号なし整数, f:浮動小数点数 } と { 8,16,32,64,128 } のビット幅の組合せです<ref>[https://crystal-lang.org/reference/1.5/syntax_and_semantics/literals/ Literals]</ref>。
 
=== for式がない?! ===
151 ⟶ 174行目:
 
=== マクロ ===
Crystalには、Rubyにはないマクロがあります<ref>[https://crystal-lang.org/reference/1.5/syntax_and_semantics/macros/ Macros - Crystal]</ref>。Rubyは実行時にすべてのオブジェクトにアクセス出来て、メソッド生やし放題なのでマクロは必要ありませんが、Crystalはコンパイル時に型やmwソッドを確定する必要があり、特にメソッドジェネレターとしてのマクロにニーズがあります。また、テンプレート言語的なマクロなので、環境変数による条件分岐や、コンテナを渡し繰返し処理する構文もあります(面白いことにマクロには for 文があり、反対にマクロの中では、eachメソッドは使えません)。マクロには <code>{{attr.id}}</code> の様にASTにアクセスする構文が用意されており、半ば言語を拡張するようなアプローチを取ることも出来ます
 
[TODO:ASTについての解説;コラム向き?]
 
;マクロを使ったattr_accessorのイミュレーション:<syntaxhighlight lang=crystal>
161 ⟶ 186行目:
macro attr_accessor(*attrs)
{% for attr in attrs %}
def {{attr.id}}() @{{attr.id}} end
def {{attr.id}}=(var) @{{attr.id}} = var end
end
def {{attr.id}}=(var)
@{{attr.id}} = var
end
{% end %}
end
188 ⟶ 209行目:
:: attr_accessor :name からは
::<syntaxhighlight lang=ruby>
def name() @name end
def name=(val) @name = val end
end
def name=(val)
@name = val
end
</syntaxhighlight>相当のコードが生成されます。
[TODO:マクロの機能と構文の説明 *の付いた引数、 <nowiki>{{</nowiki>引数}}、{% … %} 構文]