autohotkey2.0勉強中(翻訳)その8-1~関数編その1~
はじめに
翻訳とかあんま得意じゃないんだけど、関数の所らへん自分なりにまとめたやつのその1
というか関数長すぎだしプログラミング学んで浅いから知らない用語とかいろいろでわけわかめ( 一一)
その2はこちら
間違いあったらコメくれれば訂正します。というか自分用だし、間違えて覚えてしまうから(´・ω・`)
参考:ahkwiki日本語版様及び公式ヘルプ
関数編
- 関数とは、呼び出し元からのパラメータ(入力)を受け入れることができる点を除けば、サブルーチン(Gosub)と似ている
- さらに、関数は呼び出し元に値を返すこともできる
関数について基本事項
関数の定義方法
関数の定義は、以下のようにする、関数の内容が1行だけでも、「{」「}」は省略できない
ex: 関数名(パラメータリスト){ 関数本体 }
- 関数名には、半角英数字と「_」(アンダーバー)などが使用できる
- 関数名は大文字と小文字は区別されない
- パラメータリストには、パラメータの名前を「,」で区切って列挙する
- パラメータを受けとらなくていい場合は、括弧内は空にする、必ず括弧は書かないといけない
- 関数名と「(」の間には、スペースなどを入れてはいけない
- 関数本体は、必ず「{」と「}」の行で囲んでブロック化しなければならない
- 関数内では、パラメータとして与えられた値を変数のように参照することができる
- 「Return」に続いて記述した式が返り値として呼び出し元に返される
- 「Return」がない場合、空の文字列が返される
- 関数の定義は、関数定義の内部以外ならどこに書いてもかまわない
- スクリプト実行中に、関数定義の行に実行が移った場合、関数定義の終わりまではスキップされ、実行されない
ex: 2つの数値を受け取り、その合計を返す関数Addを定義する例 Add(x、y) { Return x + y "Return"のあとには式が使える }
関数の呼び出し
関数を呼び出す一般的な方法は、 := 演算子で変数に関数の結果を代入するように呼び出す
また、戻り値を無視して関数を呼び出すこともできるが、関数が返す値は破棄される
ex: 関数を呼び出して代入する例(↑)と呼び出すだけの例(↓) Var := Add(2,3) ;上の例の関数"Add"を呼び出して、返り値の5がVarに代入される Add(2,3) ;呼び出してるだけ
- 例外もあるが、パラメータリストと同じ個数のパラメータを入力しなければならない
- 関数はコマンドのパラメータ内で呼び出すことができる(OutputVarパラメータを除く)
- 関数呼び出しは式なので、関数のパラメータ内(パラメータリスト)の変数名はパーセント記号で囲まないこと
- 対照的に、文字列は二重引用符で囲む必要がある
- ただし、式をサポートしていないパラメータ内で呼び出すには、以下の例のように接頭辞「%」を使用する必要がある
- また接頭辞「%」は、式をネイティブにサポートするパラメータでも使用できるが、単に無視される
ex: 関数のパラメータに単語(文字列)foxを設定したい場合(↑)と式をサポートしていないパラメータ内で関数を呼びだす例(↓) InStr(MyVar, "fox") MsgBox % "The answer is: " . Add(3, 2)
- 関数の中からほかの関数を呼び出すことも可能である
- 呼び出しの深度の上限は159回で、160回目の呼び出しをしようとするとAutoHotkeyのプログラムが不正終了する
呼び出し元に値を返す
- 序文で説明したように、関数は呼び出し元に値を返すことができる
ex: Test := returnTest() MsgBox % Test returnTest() { return 123 ;returnのあとに値(数値、文字列、boolean値)を書くとそれが返る }
- 関数から余分な結果を返す場合は、ByRef(後述)を使用することで可能
ex: returnByRef(A,B,C) MsgBox % A "," B "," C returnByRef(ByRef val1, ByRef val2, ByRef val3) { val1 := "A" val2 := 100 val3 := 1 return }
- オブジェクトと配列を使用すると、複数の値や名前付きの値を返すことができる
ex:
Test1 := returnArray1() MsgBox % Test1[1] "," Test1[2] Test2 := returnArray2() MsgBox % Test2[1] "," Test2[2] Test3 := returnObject() MsgBox % Test3.id "," Test3.val returnArray1() { Test := [123,"ABC"] return Test } returnArray2() { x := 456 y := "EFG" return [x, y] } returnObject() { Test := {id: 789, val: "HIJ"} return Test }
関数のパラメータ
- 関数が定義の時に、パラメータは隣の括弧にリスト化して囲む
- 名前と括弧の間にスペースは入れてはいけない
- パラメータを受けとらなくていい場合は、括弧内は空にする、必ず括弧は書かないといけない
ex: パラメータいくつかの例(↑)といらない空の例(↓) function(x,y) GetCurrentTimestamp( )
ByRefパラメータ(パラメータの参照渡し)
- ByRefを定義していない限り、パラメータは基本的にローカル変数として扱われる
- ByRefを使用すると、各パラメータが呼び出し元から渡された変数のエイリアス(違う名前だけど参照は一致)になる
- つまり、パラメータに値ではなく変数の参照を渡すこと
ex: ByRefにより変数Left,Rightはグローバル変数(それぞれxとy)として扱われ、元のx,yが入れ替わる x := 12 , y := 13 Swap(x,y) MsgBox, %x% %y% Swap(ByRef Left,ByRef Right){ temp := Left Left := Right Right := temp }
- 上記の関数は、呼び出し元の変数を入れ替えるすることができる
- もし、ByRefが使用されなかった場合、LeftとRightは呼び出し元の変数のコピーであり、このSwap関数は機能しない
- returnは関数の呼び出し側に1つの値だけを返すことができるため、ByRefを使用したならば余分な結果を返すことができる
- これは、関数が値を格納する変数(通常は空)に呼び出し元を渡すことによって実現される
- 何言ってるかよくわかんない、試してみたけど解釈と違う結果になった
Tips
- 長い文字列を関数に渡すとき、ByRefを用いればその文字列のコピーを作成しなくていいので、パフォーマンスが向上するうえにメモリを節約できる
- 同様に、ByRefを使って長い文字列を呼び出し側に返すのは、普通にReturnで返すのよりも優れてる
- 中身が変更可能な変数以外の値がByRefパラメーターに渡された場合、関数はキーワード"ByRef"が存在しないかのように動作する
ex: 下記の例では、A_Indexの値をiに代入するが、スワップ関数が返されると、Leftに割り当てられた値は破棄される (一個↑のSwap関数を使用してる) Swap(A_Index, i)
- IsByRef()関数を使用すると、呼び出し元が指定されたByRefパラメータに変数を提供したかどうかを判断できる
既知の制限
- オブジェクトのプロパティ(foo.barなど)、クリップボードまたはその他の組み込み変数を、参照によって関数に渡すことはできず、代わりに、関数はByRefが省略されたように機能する
- 関数は自身を再帰的に呼び出すかもしれませんが、独自のローカル変数またはByRef以外のパラメータのいずれかをByRefに渡すと、新しいレイヤのByRefパラメータは、前のレイヤではなくその名前のローカル変数を参照する
- ただし、関数がグローバル変数、静的変数、またはByRefパラメーターを自身に渡すとき、この問題は発生しない
- 関数呼び出しのパラメータが変数(たとえば、Varまたは++ VarまたはVar * = 2)に解決された場合、その変数の左または右の他のパラメータは、関数に渡される前にその変数を変更できる
- たとえば、関数の最初のパラメータがByRefでなくても、Varが最初は0である場合、func(Var、Var ++)は予期せず1と0を渡す
- この動作は直感的ではないため、将来のリリースで変更される可能性がある
- ByRefは、COMクライアントが呼び出す関数やCOMメソッドを呼び出すときに直接サポートされていず、代わりに、スクリプトは、VarTypeと値のアドレスを含むラッパー・オブジェクトを受け取るか、渡す必要がある
パラメータのデフォルト値(パラメータのオプション)
- 関数を定義するとき、そのパラメータの1つ以上をデフォルト値を設定することができまる
- 下記のように、パラメータリストのパラメータ名の後に「:=」に続いてデフォルト値を記述することで、パラメータを省略した場合にはその値が使われるようにすることが可能である
- デフォルト値として設定できるのは、数値(定数)と「""」、true、falseのみである
- 次の関数の「Z」パラメータはオプションパラメータとして認識されている
ex: Add(X、Y、Z := 0){ Return X + Y + Z }
- 呼び出し元が上記の関数に3つのパラメータを渡すと、Zのデフォルト値は無視されるが、呼び出し側が2つのパラメータだけを渡すと、Zは自動的に値0を受け取る
- オプションのパラメータをパラメータリストの途中に挿入することはできない
- 言い換えれば、最初のオプションパラメータの右側にあるすべてのパラメータもデフォルト値を設定する必要がある
- ただし、以下のように、関数を呼び出すときにパラメータリストの途中から省略可能なパラメータを省略することができる
ex: Func(1、3) Func(X、Y:= 2、Z:= 0){ ;この場合、Zはオプションでなければならないことに注意 MsgBox%X%、%Y%、%Z% }
- ByRefパラメータはデフォルト値もサポートしている
- たとえば:Func(ByRef p1 = "")
- 呼び出し元がこのようなパラメータを省略すると、関数はデフォルト値を含むローカル変数を作成する
- 言い換えれば、関数はキーワード "ByRef"が存在しないかのように振る舞う
- パラメータメータのデフォルト値は、true、false、リテラル整数、リテラル浮動小数点数、または "fox"や ""などの引用符/リテラル文字列のいずれかでなければならない
可変長パラメータ関数(バリアディック関数)
- 関数を定義するときに、最後のパラメータの後ろにアスタリスクを書いて、可変長変数としてマークし、可変数のパラメータを受け取るようにする
ex: Join(sep, params*) { for index,param in params str .= param . sep return SubStr(str, 1, -StrLen(sep)) } MsgBox % Join("`n", "one", "two", "three") MsgBox%Join( "n"、 "one"、 "two"、 "three")
- 可変長パラメータ関数が呼び出されると、関数の最終パラメータに格納されているオブジェクトを介して余剰パラメータにアクセスできる
- 第1の余剰パラメータはparams [1]にあり、第2の余剰パラメータはparams [2]に、、これは標準オブジェクトであるため、params.Length()を使用してパラメータの数を決定できる
Tips
- 可変長パラメータはパラメータリストの最後にのみ使用できる
- RegExコールアウトは可変ではない 可変長パラメータは許容されるがブランクのままになる
- コールバックは、余剰パラメータを配列ではなくアドレスで渡す
可変長パラメータ関数呼び出し
可変長子パラメータ関数は可変長のパラメータを受け入れることができるが、関数呼び出しに同じ構文を適用することによって、任意の関数にパラメータの配列を渡すことができる
ex: substrings := ["one", "two", "three"] MsgBox % Join("`n", substrings*)
Tips
- ソース配列内のパラメータの番号は1から始まる
- オプションパラメータは、配列から完全に省略することができる
- パラメータの配列には、ユーザ定義関数を呼び出すときに名前付き項目を含めることができる
- それ以外の場合はサポートされない
- ターゲット関数は、可変長パラメータであってもよく、この場合、名前付き項目は、対応する仮パラメータを持たなくてもコピーされる
- この構文は、メソッドを呼び出したり、オブジェクトのプロパティを設定または取得したりするときにも使用できる
- たとえば、Object.Property[Params*]
既知の制限
- 右端のパラメータのみを可変長パラメータとすることができる
- たとえば、Func(x, y)は可能だが、Func(x, y)は不可能
- アスタリスク(*)とパラメータリストを終了するシンボル「)」の間に空白以外の文字を入れてはならない