通常、ほとんどの静的言語では、任意のカスタム コンパイル時エラーを作成することはできません。いくつかの例外があります ( #error
C および C++ のディレクティブのように、プリプロセッサはメインのコンパイルの前に厳密に来るため、役に立ちません)。
ただし、コンパイル時にエラーをキャッチするように特別に設計された言語機能を利用できます。
型システムはあなたの友達です。
メソッドを特定の順序で呼び出すことを要求することは、API の利用者にとって不親切であり、高水準言語のコード臭です。
簡単な解決策は、両方の操作を正しい順序で実行する単一のメソッドを公開することです。より一般的には (たとえば、2 番目のメソッドを呼び出す必要がない場合)、2 番目のメソッドが一番上にある 1 番目のメソッドを呼び出すようにします。しかし、呼び出しを API コンシューマーの制御下に置きたいと考えています。
その場合、コードをリファクタリングして、型エラーを作成せずに間違った順序でメソッドを呼び出すことができないようにします。たとえば、一致する前に正規表現をコンパイルする必要がある正規表現ライブラリを作成しているとします。Scala では、次のようにリファクタリングします。
class Regex(pattern : String) {
private[this] var compiled : Option[CompiledData] = None
def compile() {
// do stuff
this.compiled = ...
}
def search(s : String) : MatchResult = compiled match {
case Some(c) => ... // match the string
case None => throw new IllegalStateException("must compile regex first")
}
}
に
class Regex(pattern : String) {
def compile : CompiledRegex = {
// do stuff
CompiledRegex(...)
}
}
class CompiledRegex(c : CompiledData) {
def search(s : String) : MatchResult = {
... // match the string
}
}
search
メソッドは でのみ使用可能にCompiledRegex
なり、 をCompiledRegex
呼び出すことによって取得されるため、正規表現をコンパイルすることによってそのアクションが有効になる前Regex.compile
に呼び出すことはできません。search
このセットアップは、API コンシューマーにも役立ちます。ユーザーがタイプのオブジェクトを必要MatchResult
としていて、すでに を入力しているnew Regex("[abc123]*")
場合、優れた IDE は必要なメソッドをオートコンプリートまたは提案できるためです.compile
。これは元の設定では不可能です。
(この例では、Scala ではしばしば回避される可変状態も不要になりました。)
静的アサーション
別の解決策として、一部の言語 (あなたがリストしたものではありませんが、D と C++11 だと思います) は静的アサーションをサポートしています。