コンテナへの参照
ほとんどの場合、スクリプト内のコンテナは、スクリプト内で直接変数名(または他のコンテナ識別子)を指定することで、コンテナに直接値を格納したり、コンテナから値を読み出したりすることで使用されます。しかし、時々、コンテナへの参照を格納することが非常に有用になることがあります。これを使って、後でそのコンテナの値にアクセスすることができます。参照はコンテナの値ではなく、コンテナのアイデンティティを保持しており、参照にアクセスすると、それが参照しているコンテナの内容を読み出したり書き込んだりします。
参照の特性
参照には、それらを使って作業を行う際に認識しておきたいいくつかの特性があります。参照がどのように動作するかを理解するための第一歩として、次の単純な変数への参照を使用した例を考えてみてください:
put 32 into age -- Ageは現在、値32を含む変数です
put a reference to age into yearsOnThePlanet -- 参照を格納する
put yearsOnThePlanet -- 32 (yearsOnThePlanetはageの値を参照します)
add 1 to age -- Ageは現在33です
put yearsOnThePlanet -- 33を出力する (参照は動的です)
上記の最初の行では、単純な値(32
)が普通の変数(age
)に割り当てられます。次の行では、変数age
への参照を変数yearsOnThePlanet
に格納します。これにより、yearsOnThePlanet
変数の値への任意のアクセスは、実際にはスクリプトの次の行で示されているように、age
変数の値にアクセスすることになります。スクリプトの最後の2行では、age
変数 の値を増やし、yearsOnThePlanet
変数が更新された値にアクセスすることを示しています。
参照は強く結びつく
参照によって確立される接続は"スティッキー"(上記の例ではyearsOnThePlanet
はage
にしっかりと接着されています)なので、割り当ては他の方向でも動作します - どちらの値を変更しても、両方の値が変わります:
put 29 into yearsOnThePlanet
put age -- 29を出力します
参照構文
参照は、container
、reference
、reference to
、refer to
の単語を使用するか、または@
記号をコンテナの前に置くことで作成できます。以下のすべてが等価です:
put container thing into watcher
set watcher to be a reference to thing
put @thing into watcher
set watcher to reference thing
set watcher to refer to thing
構文:
container aContainer
{a} reference {to} aContainer
refer to aContainer
@ aContainer
参照はリストまたはプロパティリストに格納できます
参照は、これまでの例で示したように変数に格納するだけでなく、リストのアイテムとして、またはオブジェクトまたはプロパティリストのプロパティとして格納することもできます。この場合、参照である特定のアイテムまたはプロパティにアクセスすると、それが参照しているコンテナにアクセスします。次の例で示しています:
put 13 into luckyNumber
put ["horseshoe", container luckyNumber, "penny"] into charms
put charms -- [horseshoe, 13, penny]
put 7 into item 2 of charms
put charms -- [horseshoe, 7, penny]
put luckyNumber -- 7
参照はプロパティ、ファイル、チャンクを指すことができます
参照は、変数だけでなく、任意の種類のコンテナを参照することができます。これには、このセクションの前半部分で説明したすべての異なる種類のコンテナが含まれ、プロパティ、ファイル、さらには任意のコンテナのチャンクを含みます:
set highScore to reference item 2 of line 3 of file "/tmp/stats"
put @ item 2 delimited by "." of the numberFormat into decimalFormat
参照は動的です
オブジェクトのプロパティやコンテナのチャンク(reference to word 3 of sentence
のような)への参照が作成されると、その参照は使用されるたびに動的に評価されます。これは、sentence
の内容が変更された場合でも、参照は常に新しい内容の3番目の単語にアクセスすることを意味します。
参照は"感染性"がありません
SenseTalkの代入は、明示的に参照が示されていない限り、常に値によって行われます。したがって、参照を含む変数を別の変数に代入すると、別の参照は作成されず、ソースコンテナの現在の値のコピーだけが作成されます。別の参照を作成するには、代入時に明確に 参照を指定する必要があります(参照への参照を指定すると、同じソースへの2つ目の参照が作成されます)。
put 123 into source
put a reference to source into ref -- 123 (ref is a reference)
put ref into number -- 123 (number is NOT a reference)
put @ref into ref2 -- 123 (ref2 is now another reference to source)
put 456 into source
put ref -- 456
put number -- 123
put ref2 -- 456
参照は再割り当て可能です
すでに参照を含む変数に参照を格納すると、その変数は新しい参照に単純に再割り当てされます。以前参照していた変数の値は変わりません:
put [123, 456] into [source1, source2]
put a reference to source1 into ref
put ref -- 123
put a reference to source2 into ref -- Ref is now reassigned
put 789 into ref -- Source1 is unaffected
put [source1, source2] -- [123, 789]
元の参照変数を再割り当てするのではなく、参照していたコンテナを参照に変更するには、container referred to
を使用して明示的に要求することができます:
put @source1 into the container referred to by ref -- Ref still refers to source2, which now becomes a reference to source1
put "We're Twins" into ref -- Assign to ultimate container
put [source1, source2] -- [We're Twins,We're Twins]
参照による 削除
delete
コマンドを使用してチャンクやプロパティへの参照を削除すると、参照しているチャンクやプロパティが削除されます(これは参照を含む変数を削除するのとは異なることに注意してください - 下記参照)。
put [1,3,5,7,9,11,13] into odds
set num to refer to item 5 of odds
put num -- 9 (num refers to item 5)
delete num
put odds -- [1,3,5,7,11,13]
put num -- 11 (num now refers to the new item 5)
参照は持続的です
変数が一度参照になると、それは別の参照に再割り当てされるか、または参照自体が削除されるまで、それが参照するコンテナに結びついたままです。単にそれに空を入れることで参照変数を他の用途のために解放できると思うかもしれませんが、これは単にそれが参照するコンテナに空を入れるだけです! 変数を他の目的のために使用するためには、最初に delete variable
コマンド( delete
コマンドではない - 上記参照)を使用して削除する必要があります。参照がリストのアイテムやオブジェクトのプロパティとして保存されている場合、そのアイテムやプロパティを削除できます。
"green"をsourceにputする
localColorをsourceを参照するように設定する
localColorを"yellow"に設定する
sourceをputする -- "yellow"
delete variable localColor -- LocalColorは現在未定義(もはや参照ではない)
localColorを"blue"に設定する -- 自身の値を割り当てる
sourceをputする -- "yellow"
参照が明示的に削除されずに普通の変数になる2つの特殊なケースがあります。特殊な変数 it
の値を暗黙的に設定するコマンド(All About "it"のリスト参照)は、新しい値を割り当てる前に it
に格納された任意の参照を最初に切断します。また、repeat構造が現在参照であるループ変数を指定する場合、その参照は変数がrepeatで使用される前にクリアされます。
参照の使用
参照はスクリプトの多くの場面で使用することができます。ここでは、最も一般的な使用 法のいくつかを紹介します。
参照によるパラメータの渡し
参照の一般的な使用法の一つは、他のハンドラに参照をパラメータとして渡すことです。参照を渡すことにより、呼び出されたハンドラはローカルハンドラ内の値を変更することができます。以下に例を示します:
"candy"をtastyFoodにputする
pluralize @tastyFood -- 参照により渡す
put tastyFood
to pluralize aWord
もしaWordが "y"で終わっていたら、aWordの最後の文字に "ies"をputする
そうでなければ、aWordの後に "s" を追加する
pluralizeを終了する
上のスクリプトを実行すると、"candies"が表示されます。tastyFoodという変数は初期ハンドラからpluralizeハンドラに参照として渡されます。これが参照であるため、aWordがpluralizeハンドラによって変更されると、実際には初期ハンドラのtastyFood変数の値が変更されます。
参照の戻り / 関数結果をコンテナとして使用する
他のハンドラに参照を渡すと、そのハンドラは参照が指すコンテナの内容を変更する能力を得るのと同じように、関数が呼び出し元がその後変更できるコンテナへの参照を返すことが有用なことがあります。たとえば、関数はグローバル変数や関数によって選択されたファイル、あるいはそのようなコンテナのチャンクへの参照を返すかもしれません。これを行うためには、2つのことが起こらなければなりません。第一に、呼び出される関数は参照を返さなければなりません。第二に、呼び出し側のハンドラは、戻り値をコンテナとして使用したいと指示しなければなりません(デフォルトでは、関数の戻り値は常に値として扱われます)。
例として、どちらのリストが少ないアイテムを持っているかによって、2つのリストのいずれかに値を挿入したいとします(より現実的な例では、複数のリストが関与するかもしれません)。以下に、このアイデアを実装するスクリプトを示します。このスクリプトでは、適切なリストを選択するための関数を使用しています:
"a,b,c,d,e,f"をfirstBoxにputする
"9,8,7,6"をsecondBoxにputする
container chooseContainer(@firstBox, @secondBox)の後に",Here"をputする
firstBoxをputする -- "a,b,c,d,e,f"
secondBoxをputする -- "9,8,7,6,Here"
chooseContainerという名前のコンテナを定義します @c1, @c2
もしc1のアイテムの数がc2のアイテムの数より少ない場合
それからコンテナc1を返します
そうでなければコンテナc2を返します
chooseContainerを終了する
この例では、多くの参照があります。関数呼び出しの戻り値をコンテナとして扱うようにSenseTalkに指示するために、chooseContainer()
の前に"container"(または"@"または"reference")が必要です。この例を動作させるためには、パラメータも参照として渡されなければなりません(@firstBox
, @secondBox
)これは、それらが呼び出しスクリプトから来るからです。そしてもちろん、選択されたコンテナは参照として返されなければなりません。結果として、任意の2つのコンテナへの参照を受け入れ、アイテムが少ないコンテナへの参照を返す関数が得られます。関数の入力パラメータを参照としてマークする(@c1, @c2
)はオプションで あり、現在のSenseTalkのバージョンでは機能的な意味はありませんが、chooseContainer関数のユーザに、パラメータは参照として渡されるべきであることを思い出させるのに役立ちます。
値が参照であるかどうかを判断する
前述の例では、chooseContainer()関数は、そのパラメータの前に"@"記号を使用することによって、ユーザに対して参照を使って呼び出すべきであることを示しています(@c1
, @c2
)。しかし、SenseTalkはこれを何ら強制しません。関数をより堅牢にするために、実際にパラメータが参照として渡されたかどうかをチェックし、間違って呼び出された場合にユーザに警告することができます。この目的のために、is a
(またはis not a
)オペレータを使用できます。以下に、このテストを行う関数の改良版を示します:
chooseContainerという名前のコンテナを定義します @c1, @c2
もしc1が参照でない、またはc2が参 照でない場合
"Not A Reference", "コンテナは参照で渡す必要があります"というメッセージを投げます
end if
もしc1のアイテムの数がc2のアイテムの数より少ない場合
それからコンテナc1を返します
そうでなければコンテナc2を返します
chooseContainerを終了する
Repeat With Each ... By Reference
repeat with each
コマンドの特別な "by reference" オプションは、イテレータ変数を現在の要素への参照に設定します。これは単にその値ではありません。これは、コンテナのチャンクを反復処理するだけでなく、その要素の一部に変更を加えるスクリプトを書くことを大幅に簡素化します。以下に例を示します:
"come all you good people and make merry" を phrase に入れます
phrase の各単語を参照で反復します
もし、それの最後の文字が "aeiou" になければ、それの後ろに "e" を追加します
もし、それが "you" なら、それを "ye" に設定します
反復を終了します
phraseを表示します -- "come alle ye goode people ande make merrye"