2

この問題をどのように解決しますか?

次のことを行う関数を書きたいとします。ユーザーがライブラリ X をインストールしている場合は関数 X 関数を使用し、それ以外の場合はスキップしますか?

私が試したこと:

(when (symbol-function 'X-function)
  (X-function))

このコードに対して警告が表示されます。正しい方法は何ですか?

4

3 に答える 3

4

これはどう:

(when (fboundp 'X-function)
    (X-function))

http://www.gnu.org/software/emacs/manual/html_node/elisp/Function-Cells.htmlのドキュメントには、symbol-functionについて書かれています。

シンボルの関数セルがvoidの場合、void関数エラーが通知されます。

それがあなたが見ているものだと思います。一方、fboundpは、関数が存在するかどうかに応じて、tまたはnilを返すだけです。

于 2012-09-26T23:27:00.643 に答える
4

このコンパイラの警告を抑制する方法は、次のようなものです。

(declare-function X-function "ext:X-library.el")

(when (fboundp 'X-function)
     (X-function))

ここで、X-library は、X-function が定義されているライブラリーの名前です。次に、バイトコンパイラは次のことを行います。

  1. ロード パスでライブラリが検索されます。
  2. 見つかった場合は、関数が定義されていることを確認します。
  3. ライブラリが見つからない場合は、ライブラリがそこにあると想定し、エラーなしで渡します。

したがって、X-library が存在しない場合は文句を言いませんが、X-library があり、関数を定義していない場合は文句を言います。これは、ライブラリの更新されたバージョンに X 関数が含まれていない場合、コードを再コンパイルしようとしたときにわかることを意味します。

declare-function のドキュメントを調べると、関数の引数リストもチェックできることがわかります。

ちなみに、宣言されていない変数について同様の警告が表示された場合は、次の方法でこれらを抑制することができます。

(defvar X-variable)

ただし、ライブラリが設定する値がわかっている場合でも、変数を設定しないことが重要です。これは、後のバージョンで変更される可能性があるためです。

これにより、X-library が存在するかどうかにかかわらず機能する 1 つのバージョンのプログラムが得られます。X-library が存在する場合と存在しない場合の 2 つのバージョンを用意することをお勧めします。これは、マクロを使用して実行できます。

(defmacro run? (function &rest args)
  "Expand to function call if function exists."
  (when (fboundp `,function)
    `(,function ,@args)))

次のような呼び出しの代わりに:

(X-function a1 a2 a3)

あなたが書く:

(run? X-function a1 a2 a3)

X-library が存在する状態でコンパイルすると、これは X-function の呼び出しに展開されます。ライブラリが存在しない場合、何も展開されません。いずれの場合も、declare-function は必要ありません。これにより2つの異なるバージョンが得られますが、ライブラリが存在するかどうかの決定は実行時ではなくコンパイル時に行われるため、より効率的です。

1 つの小さな警告。この 2 番目のソリューションを使用する場合は、プログラム全体を X-library 環境またはその外部でコンパイルする必要があります。プログラムの途中でライブラリをロードしようとすると、解釈されたときに、ロードの前後でマクロの展開が異なるため、期待どおりに機能します。しかし、コンパイルされたプログラムでは、マクロは一度だけ展開されます。ライブラリのテスト テストは、展開ではなく展開を行うコード内にあるため、マクロはロードの前後で同じようには機能しません。

于 2012-11-27T16:00:41.400 に答える
0

関数が見つからないという警告が表示される別のケースとして、関数をプログラムで定義し、fsetを使用して設定する場合があります。次の例は、これとその対処方法を示しています。

(eval-and-compile
  (fset 'my-function1 (lambda () nil)))

(my-function1)

(fset 'my-function2 (lambda () nil))

(my-function2)

(my-function3)

(eval-and-compile
  (fset 'my-function3 (lambda () nil)))

これをコンパイルすると、次の警告が表示されます。

Warning: the function `my-function2' is not known to be defined.

と:

Warning: the function `my-function3' might not be defined at runtime.

同じ Emacs セッションでもう一度コードを再コンパイルすると、2 番目の警告は消えますが、最初の警告は消えません。

ここで起こっていることは次のとおりです: コンパイラがeval-and-compileを検出すると、まず現在の Emacs セッションで の本体を評価してからコンパイルします。コードを評価すると、Emacs はプログラムで定義された関数を認識します。

  1. function1の場合、バイト コンパイラは、Emacs がフォームを評価した後に関数呼び出しを確認するため、警告は表示されません。
  2. function2の場合、バイトコンパイラは関数が定義されていることを認識しないため、常に警告が表示されます。
  3. function3の場合、最初のラウンドでは、bit コンパイラは関数呼び出しを確認したときに関数が存在することを知りません。コンパイルの終わりまでに、関数が存在することを認識していますが、それがどのように認識されているかを理解するのに十分なほどインテリジェントではないため、別の警告が表示されます。ただし、同じ Emacs セッションで再コンパイルすると、認識されるため、警告は消えます。

eval-and-compileは、eval-with-compileと同様に、Emacs インタープリターにとってはprognのように見えることに注意してください。

于 2012-12-13T22:20:54.857 に答える