ジェネリックGenerics

F# の関数値、メソッド、プロパティ、および集約型 (クラス、レコード、判別共用体など) は、ジェネリックにすることができます。F# function values, methods, properties, and aggregate types such as classes, records, and discriminated unions can be generic. ジェネリック コンストラクトには、少なくとも 1 つの型パラメーターが含まれます。この型は、通常、ジェネリック コンストラクトのユーザーによって指定されます。Generic constructs contain at least one type parameter, which is usually supplied by the user of the generic construct. ジェネリック関数とジェネリック型を使用すると、型ごとにコードを繰り返し記述しなくても、さまざまな型で動作するコードを記述できます。Generic functions and types enable you to write code that works with a variety of types without repeating the code for each type. 多くの場合、F# のコードは、コンパイラの型推論と自動ジェネリック化メカニズムによって、暗黙的にジェネリックとして推論されるため、F# では、コードを簡単にジェネリックにできる可能性があります。Making your code generic can be simple in F#, because often your code is implicitly inferred to be generic by the compiler's type inference and automatic generalization mechanisms.

構文Syntax

// Explicitly generic function.
let function-name<type-parameters> parameter-list =
function-body

// Explicitly generic method.
[ static ] member object-identifer.method-name<type-parameters> parameter-list [ return-type ] =
method-body

// Explicitly generic class, record, interface, structure,
// or discriminated union.
type type-name<type-parameters> type-definition

RemarksRemarks

明示的なジェネリック関数やジェネリック型の宣言は、非ジェネリックの関数や型の宣言によく似ていますが、型パラメーターの指定 (および使用) 方法が異なり、型パラメーターは、関数名または型名の後ろに山かっこで囲んで指定します。The declaration of an explicitly generic function or type is much like that of a non-generic function or type, except for the specification (and use) of the type parameters, in angle brackets after the function or type name.

宣言は、多くの場合、暗黙的にジェネリックになります。Declarations are often implicitly generic. 関数または型の作成に使用されるすべてのパラメーターの型が完全に指定されていない場合、コンパイラは、記述されたコードから、それぞれのパラメーター、値、および変数の型を推論しようと試みます。If you do not fully specify the type of every parameter that is used to compose a function or type, the compiler attempts to infer the type of each parameter, value, and variable from the code you write. 詳細については、「Type Inference」を参照してください。For more information, see Type Inference. 型や関数のコードによってパラメーターの型が特に制約されない場合、その関数または型は暗黙的にジェネリックとなります。If the code for your type or function does not otherwise constrain the types of parameters, the function or type is implicitly generic. このプロセスは、自動ジェネリック化と呼ばれます。This process is named automatic generalization. 自動ジェネリック化にいくつかの制限があります。There are some limits on automatic generalization. たとえば、F# コンパイラがジェネリック コンストラクトの型を推論できない場合、コンパイラは、値の制限と呼ばれる制約を示すエラーを報告します。For example, if the F# compiler is unable to infer the types for a generic construct, the compiler reports an error that refers to a restriction called the value restriction. この場合、型の注釈の追加が必要になることがあります。In that case, you may have to add some type annotations. 自動ジェネリック化と値の制限の詳細、およびコードを変更して問題に対処する方法については、「自動ジェネリック化」を参照してください。For more information about automatic generalization and the value restriction, and how to change your code to address the problem, see Automatic Generalization.

前の構文の type-parameters は、未知の型を表すパラメーターのコンマ区切りのリストです。それぞれは単一引用符から開始し、必要に応じて、その型パラメーターで使用できる型をさらに制限する制約句を指定します。In the previous syntax, type-parameters is a comma-separated list of parameters that represent unknown types, each of which starts with a single quotation mark, optionally with a constraint clause that further limits what types may be used for that type parameter. 制約句の構文および制約に関するその他の情報については、「制約」を参照してください。For the syntax for constraint clauses of various kinds and other information about constraints, see Constraints.

構文の type-definition は、非ジェネリック型の型定義と同じです。The type-definition in the syntax is the same as the type definition for a non-generic type. これには、クラス型のコンストラクター パラメーター、オプションの as 句、等号、レコード フィールド、inherit 句、判別共用体の選択、let バインドと do バインド、メンバー定義、および非ジェネリック型定義で許可されている他の任意の記述が含まれます。It includes the constructor parameters for a class type, an optional as clause, the equal symbol, the record fields, the inherit clause, the choices for a discriminated union, let and do bindings, member definitions, and anything else permitted in a non-generic type definition.

その他の構文要素は、非ジェネリック関数および非ジェネリック型と同じです。The other syntax elements are the same as those for non-generic functions and types. たとえば、object-identifier は、それを含むオブジェクト自体を表す識別子です。For example, object-identifier is an identifier that represents the containing object itself.

プロパティ、フィールド、およびコンストラクターは、それを囲む型よりもジェネリックにすることはできません。Properties, fields, and constructors cannot be more generic than the enclosing type. また、モジュール内の値をジェネリックにすることもできません。Also, values in a module cannot be generic.

暗黙的なジェネリック コンストラクトImplicitly Generic Constructs

F# コンパイラがコード内の型を推論するとき、ジェネリックにできる関数はすべて自動的にジェネリックとして扱われます。When the F# compiler infers the types in your code, it automatically treats any function that can be generic as generic. パラメーター型など、型を明示的に指定すると、自動ジェネリック化を回避できます。If you specify a type explicitly, such as a parameter type, you prevent automatic generalization.

次のコード例では、makeList とそのパラメーターはいずれもジェネリックとして明示的に宣言されていませんが、makeList はジェネリックになります。In the following code example, makeList is generic, even though neither it nor its parameters are explicitly declared as generic.

let makeList a b =
    [a; b]

関数のシグネチャは、'a -> 'a -> 'a list と推論されます。The signature of the function is inferred to be 'a -> 'a -> 'a list. この例で、ab は同じ型と推論されることに注意してください。Note that a and b in this example are inferred to have the same type. これは、いずれも同じリストに含まれており、1 つのリスト内の要素はすべて同じ型でなければならないためです。This is because they are included in a list together, and all elements of a list must be of the same type.

関数をジェネリックにするには、型の注釈で単一引用符の構文を使用して、パラメーター型がジェネリック型パラメーターであることを示す方法もあります。You can also make a function generic by using the single quotation mark syntax in a type annotation to indicate that a parameter type is a generic type parameter. 次のコードでは、この方法でパラメーターが型パラメーターとして宣言されているため、function1 はジェネリックになります。In the following code, function1 is generic because its parameters are declared in this manner, as type parameters.

let function1 (x: 'a) (y: 'a) =
    printfn "%A %A" x y

明示的なジェネリック コンストラクトExplicitly Generic Constructs

山かっこ (<type-parameter>) 内で型パラメーターを明示的に宣言することで、関数をジェネリックにすることもできます。You can also make a function generic by explicitly declaring its type parameters in angle brackets (<type-parameter>). 次に例を示します。The following code illustrates this.

let function2<'T> x y =
    printfn "%A, %A" x y

ジェネリック コンストラクトの使用Using Generic Constructs

ジェネリック関数またはジェネリック メソッドを使用する場合、型引数を指定しなくてもよいことがあります。When you use generic functions or methods, you might not have to specify the type arguments. コンパイラは、型推論を使用して適切な型引数を推論します。The compiler uses type inference to infer the appropriate type arguments. あいまいさが残っている場合は、山かっこ内に型引数を指定できます。複数の型引数を指定する場合はコンマで区切ります。If there is still an ambiguity, you can supply type arguments in angle brackets, separating multiple type arguments with commas.

次のコードでは、前のセクションで説明した関数の使用方法を示します。The following code shows the use of the functions that are defined in the previous sections.

// In this case, the type argument is inferred to be int.
function1 10 20
// In this case, the type argument is float.
function1 10.0 20.0
// Type arguments can be specified, but should only be specified
// if the type parameters are declared explicitly. If specified,
// they have an effect on type inference, so in this example,
// a and b are inferred to have type int.
let function3 a b =
    // The compiler reports a warning:
    function1<int> a b
    // No warning.
    function2<int> a b

注意

名前でジェネリック型を参照するには、2 つの方法があります。There are two ways to refer to a generic type by name. たとえば、1 つの型引数 list を持つジェネリック型 int を参照する方法として、list<int>int list の 2 つがありますFor example, list<int> and int list are two ways to refer to a generic type list that has a single type argument int. 後者の形式は、通常、listoption などの F# の組み込み型でのみ使用されます。The latter form is conventionally used only with built-in F# types such as list and option. 複数の型引数がある場合、通常は Dictionary<int, string> 構文を使用しますが、(int, string) Dictionary 構文を使用することもできます。If there are multiple type arguments, you normally use the syntax Dictionary<int, string> but you can also use the syntax (int, string) Dictionary.

型引数としてのワイルドカードWildcards as Type Arguments

引数がコンパイラによって推論される必要があることを指定するには、名前付き型引数の代わりに、アンダースコアまたはワイルドカード記号 (_) を使用できます。To specify that a type argument should be inferred by the compiler, you can use the underscore, or wildcard symbol (_), instead of a named type argument. これを次のコードに示します。This is shown in the following code.

let printSequence (sequence1: Collections.seq<_>) =
   Seq.iter (fun elem -> printf "%s " (elem.ToString())) sequence1

ジェネリック型とジェネリック関数の制約Constraints in Generic Types and Functions

ジェネリック型またはジェネリック関数の定義では、ジェネリック型パラメーターで使用できることがわかっているコンストラクトのみを使用できます。In a generic type or function definition, you can use only those constructs that are known to be available on the generic type parameter. この制限は、コンパイル時に関数呼び出しやメソッド呼び出しを検証できるようにするために必要です。This is required to enable the verification of function and method calls at compile time. 型パラメーターを明示的に宣言する場合は、ジェネリック型パラメーターに明示的な制約を適用して、特定のメソッドおよび関数を使用できることをコンパイラに通知できます。If you declare your type parameters explicitly, you can apply an explicit constraint to a generic type parameter to notify the compiler that certain methods and functions are available. ただし、F# コンパイラがジェネリック パラメーターの型を推論できるようにすると、コンパイラが自動的に適切な制約を決定します。However, if you allow the F# compiler to infer your generic parameter types, it will determine the appropriate constraints for you. 詳細については、「制約」を参照してください。For more information, see Constraints.

静的に解決される型パラメーターStatically Resolved Type Parameters

F# プログラムで使用できる型パラメーターには、2 つの種類があります。There are two kinds of type parameters that can be used in F# programs. 1 つ目は、前のセクションで説明した種類のジェネリック型パラメーターです。The first are generic type parameters of the kind described in the previous sections. 1 つ目の種類の型パラメーターは、Visual Basic や C# などの言語で使用されるジェネリック型パラメーターと同等です。This first kind of type parameter is equivalent to the generic type parameters that are used in languages such as Visual Basic and C#. もう 1 つの種類の型パラメーターは F# に固有のもので、静的に解決される型パラメーターと呼ばれます。Another kind of type parameter is specific to F# and is referred to as a statically resolved type parameter. これらのコンストラクトの詳細については、「Statically Resolved Type Parameters」を参照してください。For information about these constructs, see Statically Resolved Type Parameters.

使用例Examples

// A generic function.
// In this example, the generic type parameter 'a makes function3 generic.
let function3 (x : 'a) (y : 'a) =
    printf "%A %A" x y

// A generic record, with the type parameter in angle brackets.
type GR<'a> =
    {
        Field1: 'a;
        Field2: 'a;
    }

// A generic class.
type C<'a>(a : 'a, b : 'a) =
    let z = a
    let y = b
    member this.GenericMethod(x : 'a) =
        printfn "%A %A %A" x y z

// A generic discriminated union.
type U<'a> =
    | Choice1 of 'a
    | Choice2 of 'a * 'a

type Test() =
    // A generic member
    member this.Function1<'a>(x, y) =
        printfn "%A, %A" x y

    // A generic abstract method.
    abstract abstractMethod<'a, 'b> : 'a * 'b -> unit
    override this.abstractMethod<'a, 'b>(x:'a, y:'b) =
         printfn "%A, %A" x y

関連項目See also