トラブルシューティング & よくある間違い
LuneScript の学習中に遭遇しやすいエラーとその解決方法をまとめました。
他の言語(特に Lua, Go, Rust など)の経験者がハマりやすいポイントを中心に解説します。
文字リテラルの構文
間違い: シングルクォートを使ってしまう
// @lnsFront: skip
let c = 'a'; // Error
let c = ?'a'; // Error
正解: ? の直後に文字を書く
// @lnsFront: skip
let c = ?a; // 文字コード (int) になる
let sp = ? ; // スペースの場合も同様
let zero = ?0; // 数字の文字コード
LuneScript では、文字リテラルは整数値(文字コード)として扱われます。
ミュータブルなメソッド定義
間違い: mut を前置してしまう
// @lnsFront: skip
class MyClass {
let mut val: int;
// Error: illegal field or method declaration
pub mut fn inc() {
self.val = self.val + 1;
}
}
正解: mut は引数リストの後ろに置く
// @lnsFront: skip
class MyClass {
let mut val: int;
// メソッドが自身 (self) を書き換えることを示す
pub fn inc() mut {
self.val = self.val + 1;
}
}
メソッド定義において、mut は「このメソッドは self
を変更する」という副作用の宣言として機能するため、シグネチャの一部(後ろ側)に記述します。
なお、戻り値がある場合は pun fn func() mut : int のように戻り値の型の前になります。
ADT のパターンマッチ
間違い: if let を使おうとする (Rust風)
// @lnsFront: skip
// Error: illegal exp
if let .Val( v ) = val {
print( v );
}
正解: match 文を使用する
// @lnsFront: skip
match val {
case .Val( v ) {
print( v );
}
default {
// マッチしなかった場合の処理
}
}
LuneScript の現行バージョンでは、代数的データ型 (Algebric Data Type) の分解には match 文を使用するのが基本です。
Nilable 型の操作と unwrap
間違い: Nilable 型をそのまま非 Nilable として扱う
// @lnsFront: skip
let val: int! = 10;
// Error: type mismatch int! (nilable) to int
let num: int = val;
正解: unwrap を使って安全に取り出す
// @lnsFront: skip
let val: int! = 10;
// nil だった場合のデフォルト値を指定する
let num: int = unwrap val default 0;
// または if let で絞り込む
if let v = val {
print( v ); // ここでは v は int 型
}
unwrap は「値が nil でないことを保証する」か「nil の場合の代替値を提供する」ために使われます。
マクロの構文エラー
間違い: 展開演算子 ,, を忘れる
// @lnsFront: skip
macro _dprint( val: __exp ) {
print( val ); // Error: val は __exp 型であり、そのままでは使えない
}
正解: ,, を使って式を展開する
// @lnsFront: skip
macro _dprint( val: __exp ) {
print( ,,val ); // OK: 式が展開される
}
マクロ引数(__exp, sym, __block など)をコード内で利用するには、必ず ,,
で展開する必要があります。
間違い: Lua の予約語をシンボル名に使ってしまう
// @lnsFront: skip
macro _measure( block: __block ) {
{}
{
let start = os.clock();
,,block
let end = os.clock(); // Error: 'end' は Lua の予約語
print( end - start );
}
}
正解: 予約語を避けた名前にする
LuneScript は Lua に変換されるため、マクロで展開されるコード内の変数名が Lua の予約語(end, function,
repeat など)と衝突するとエラーになります。endTime などの別の名前に変更してください。
間違い: __block 引数に直接ステートメントを書く
// @lnsFront: skip
_measure( print("hello") ); // Error: 式ではなくブロック {} が必要
正解: {} で囲って渡す
// @lnsFront: skip
_measure( { print("hello"); } );
また、LuneScript の最新の文法では __block の代わりに ##
を使った引数省略機能の利用が推奨される場合があります。コンパイラの警告に従って調整してください。
間違い: macro-statement 内で通常の関数を定義・呼び出ししようとする
// @lnsFront: skip
macro _Test() {
{
fn createFunc( name: str ): stat { // Error
return `{ fn ,,,name() {} };
}
}
,,createFunc("hoge");
}
正解: macro-statement は制限された環境であることを理解する
macro-statement ブロック内では、型システムやユーザー定義関数が完全に利用できるわけではありません。基本的には、組込み型と組込み関数を用いた計算、および
`{} によるコード生成に専念させるのが安全です。
間違い: ,,, 演算子の範囲が不明確
// @lnsFront: skip
stats.insert( `{
let ,,, "v_%s"(name) = ,,i; // Error: どこまでが名前生成式か不明
} );
正解: ~~ で終端を明示する
// @lnsFront: skip
stats.insert( `{
let ,,, "v_%s"(name) ~~ = ,,i; // OK: ~~ で式の終わりを教える
} );
シンボルを動的に生成する ,,, 演算子は、その後に続く要素と結合して解釈されるのを防ぐため、~~ による区切りが必要になるケースが多々あります。