zshにクロージャのようなものがありますか?

zshにクロージャのようなものがありますか?

私はoh-my-zshでzshを試すことにしましたが、precmd最後の行に正しいプロンプトがない2行のプロンプトをエミュレートしようとしています。

だから基本テーマを複製してインスピレーションを得ました。この投稿(私はそれをたくさん学ぶためにも使います)、私は次のようにしました(後で色を追加します):

function precmd {
    local cwd="${(%):-[%~]}"
    local who_where="${(%):-%n@%m}"
    local git_info=${(%)$(git_prompt_info)}
    local right_prompt="     $git_info [$who_where]"
    local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"

    echo "$left_prompt$right_prompt"
}

効果があるしかし、不思議ではありません。 precmdが呼び出されるたびにzshはこれらすべての変数を定義しますか?

私はzshに関連するクロージャ、スコープ、名前空間についてインターネット検索を行っており、変数を毎回上書きする必要がないようにローカル変数をprecmdにデータとして追加したいと思いましたが、何も見つかりませんでした。私がやっていることをする方法がありますか、それともあきらめなければなりませんか?

参考までに関連性がある場合にのみ、「関数のロード」とはどういう意味ですか?

答え1

Zshにはクロージャ、パッケージ、名前空間などはありません。 Zshには、実際のクロージャを実装するために必要なものがありません。

  • 機能は最高レベルではありません。関数を他の関数に引数として渡すことはできず、関数は他の関数を返すことはできません。 (これは次の方法で行うことができます。名前呼び出す関数の名前ですが、関数自体を渡すのとは異なります。

  • 入れ子になった関数はありません。 zshのすべての機能はグローバルです。競合を避けるには、関数名の前にプレフィックスを付ける必要があります。特に、この機能は同じ名前の外部プログラムを隠すことに注意してください。という関数があると、lsプログラムの代わりにその関数が呼び出されますls。間違えない限り、これは役に立ちます。

  • 変数の範囲は、ほとんどの現代言語のように静的ではなく動的です。入れ子になった関数があっても、内部関数は通常予想される方法で外部関数のローカル変数を閉じません。人々がJavascriptを使用するようにモジュールを作成するために使用することはできません。

  • ジッシュする匿名関数もありますが、他に何もなければあまり役に立ちません。

したがって、基本的に最善の方法は、すべての関数とグローバル変数に接頭辞を付けることです。

precmdまた、次のように定義する必要があることを指摘したいと思います。

% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function

add-zsh-hookprecmdリンクしたい他の関数を上書きせずに関数をリンクできますprecmd

関数のロードが何を意味するかは別の質問です。 Zshには、実際に呼び出されたときにのみディスクから関数をロードする自動ロード機能があります。これにより、autoload -Uz foobar名前付き関数を呼び出すことができます。foobar実際に呼び出すと、foobar定義はディスクからロードされます。

答え2

いいえ、クロージャはzshと比較して複雑すぎます。 Zsh は、直接的な相互作用から大きく逸脱しない小さなスクリプトを解釈するように設計されています。大規模なプログラミングに役立つ素晴らしい言語機能はありませんが、通常はシェルを使用して実行する小さな操作にはあまり便利ではありません。

変数の値を事前に計算して完全に保存できるクロージャ型がある場合、一部の変更によって情報が無効になったときにその値は更新されません。

$git_info派生変数は、gitまたはgitリポジトリにチェックインされたファイルの変更により、いつでも変更できます。したがって、とにかく毎回再計算する必要があります。

cwdグローバル変数の値はwho_where通常の操作では変更されないため、キャッシュできます。cwd現在のディレクトリが変更されると、現在のディレクトリも変更されるため、から変更する必要がありますchpwd。しかし、これらの変数は非常に迅速に計算されるので、面倒にする必要はありません。ここでは高価な計算が実行されており、git_prompt_infoいつでも変更される可能性があります。

PS1各コマンド間で情報を表示するときは、プロンプト(または配列)の一部として実行するのが最善ですpsvar。 Zshはさまざまな状況でプロンプトを再表示する必要があることを知っていますが、印刷した内容については何もわかりませんprecmd

答え3

はい、これらの変数は関数が呼び出されるたびに(再)定義されます。

一度だけ初期化したい場合は、関数の最上位レベルに簡単に移動できます。

答え4

クロージャを実装するには、言語が関数を要素またはオブジェクトとして機能できる必要があります。これは、文字列と組み込み関数eval(他のシェルのように)を介さないとzshでは不可能です。ただし、参照などのすべての下位レベルの項目を直接処理する必要があるため、これは非常に制限的です。ただし、引数に特殊文字がない場合(したがって参照を処理する必要がない場合)、このアイデアを使用して簡単な操作を実行するのは簡単で、zshでは匿名関数が少し役に立ちます。たとえば、a*x+b*yと は関数定義時に提供される定数でaあり、関数の引数である計算関数を定義するには、次のようにします。bxy

mk_ax_plus_by() { echo "() { echo \$((($1)*(\$1)+($2)*(\$2))) }" }

fct_2x_plus_3y=$(mk_ax_plus_by 2 3)
fct_5x_plus_7y=$(mk_ax_plus_by 5 7)

fct_2x_plus_3yしたがって、計算関数2*x+3*yfct_5x_plus_7y計算関数があります5*x+7*y(読みやすくするために関数名を選択したことに注意してください。これらの名前は何でも可能で、内容を変数に保存する必要はありません)。また、これらは実際には文字列(シェル用語では関数ではありません)ですが、組み込みeval関数のように動作します。使用例:

% eval $fct_2x_plus_3y 4 9
35
% eval $fct_5x_plus_7y 4 9
83

2*4+3*935を与え、5*4+7*983を与えます。

関数型言語とは異なり、ここでは環境から来るパラメータ(引用符なし)と関数を定義するパラメータ(引用符付き)を区別する必要があります。つまり、関数が呼び出されたときにのみ評価されます。ただし、実装は機能言語と同様に変更でき、使用法は同じです。

mk_ax_plus_by()
{
  local x='$1' y='$2'
  echo "() { echo \$((($1)*($x)+($2)*($y))) }"
}

関連情報