Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

dart.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.

Learn more
Generics

Dart 3.11 is live!Learn more

Generics

Learn about generic types in Dart.

If you look at the API documentation for the basic array type,List, you'll see that the type is actuallyList<E>. The <...> notation marks List as ageneric (orparameterized) type—a type that has formal type parameters.By convention, most type variables have single-letter names, such as E, T, S, K, and V.

Why use generics?

#

Generics are often required for type safety, but they have more benefits than just allowing your code to run:

  • Properly specifying generic types results in better generated code.
  • You can use generics to reduce code duplication.

If you intend for a list to contain only strings, you can declare it asList<String> (read that as "list of string"). That way you, your fellow programmers, and your tools can detect that assigning a non-string to the list is probably a mistake. Here's an example:

static analysis: failuredart
varnames=<String>[];names.addAll(['Seth','Kathy','Lars']);names.add(42);// Error

Another reason for using generics is to reduce code duplication. Generics let you share a single interface and implementation between many types, while still taking advantage of static analysis. For example, say you create an interface for caching an object:

dart
abstractclassObjectCache{ObjectgetByKey(Stringkey);voidsetByKey(Stringkey,Objectvalue);}

You discover that you want a string-specific version of this interface, so you create another interface:

dart
abstractclassStringCache{StringgetByKey(Stringkey);voidsetByKey(Stringkey,Stringvalue);}

Later, you decide you want a number-specific version of this interface... You get the idea.

Generic types can save you the trouble of creating all these interfaces. Instead, you can create a single interface that takes a type parameter:

dart
abstractclassCache<T>{TgetByKey(Stringkey);voidsetByKey(Stringkey,Tvalue);}

In this code, T is the stand-in type. It's a placeholder that you can think of as a type that a developer will define later.

Using collection literals

#

List, set, and map literals can be parameterized. Parameterized literals are just like the literals you've already seen, except that you add<type> (for lists and sets) or<keyType,valueType> (for maps) before the opening bracket. Here is an example of using typed literals:

dart
varnames=<String>['Seth','Kathy','Lars'];varuniqueNames=<String>{'Seth','Kathy','Lars'};varpages=<String,String>{'index.html':'Homepage','robots.txt':'Hints for web robots','humans.txt':'We are people, not machines',};

Using parameterized types with constructors

#

To specify one or more types when using a constructor, put the types in angle brackets (<...>) just after the class name. For example:

dart
varnameSet=Set<String>.of(names);

The following code creates aSplayTreeMap that has integer keys and values of typeView:

dart
varviews=SplayTreeMap<int,View>();

Generic collections and the types they contain

#

Dart generic types arereified, which means that they carry their type information around at runtime. For example, you can test the type of a collection:

dart
varnames=<String>[];names.addAll(['Seth','Kathy','Lars']);print(namesisList<String>);// true
Note

In contrast, generics in Java useerasure, which means that generic type parameters are removed at runtime. In Java, you can test whether an object is a List, but you can't test whether it's aList<String>.

When implementing a generic type, you might want to limit the types that can be provided as arguments, so that the argument must be a subtype of a particular type. This restriction is called a bound. You can do this usingextends.

A common use case is ensuring that a type is non-nullable by making it a subtype ofObject (instead of the default,Object?).

dart
classFoo<TextendsObject>{// Any type provided to Foo for T must be non-nullable.}

You can useextends with other types besidesObject. Here's an example of extendingSomeBaseClass, so that members ofSomeBaseClass can be called on objects of typeT:

dart
classFoo<TextendsSomeBaseClass>{// Implementation goes here...StringtoString()=>"Instance of 'Foo<$T>'";}classExtenderextendsSomeBaseClass{...}

It's OK to useSomeBaseClass or any of its subtypes as the generic argument:

dart
varsomeBaseClassFoo=Foo<SomeBaseClass>();varextenderFoo=Foo<Extender>();

It's also OK to specify no generic argument:

dart
varfoo=Foo();print(foo);// Instance of 'Foo<SomeBaseClass>'

Specifying any non-SomeBaseClass type results in an error:

static analysis: failuredart
varfoo=Foo<Object>();

Self-referential type parameter restrictions (F-bounds)

#

When using bounds to restrict parameter types, you can refer the bound back to the type parameter itself. This creates a self-referential constraint, or F-bound. For example:

dart
abstractinterfaceclassComparable<T>{intcompareTo(To);}intcompareAndOffset<TextendsComparable<T>>(Tt1,Tt2)=>t1.compareTo(t2)+1;classAimplementsComparable<A>{@overrideintcompareTo(Aother)=>/*...implementation...*/0;}intuseIt=compareAndOffset(A(),A());

The F-boundT extends Comparable<T> meansT must be comparable to itself. So,A can only be compared to other instances of the same type.

Using generic methods

#

Methods and functions also allow type arguments:

dart
Tfirst<T>(List<T>ts){// Do some initial work or error checking, then...Ttmp=ts[0];// Do some additional checking or processing...returntmp;}

Here the generic type parameter onfirst (<T>) allows you to use the type argumentT in several places:

  • In the function's return type (T).
  • In the type of an argument (List<T>).
  • In the type of a local variable (T tmp).
Was this page's content helpful?

Unless stated otherwise, the documentation on this site reflects Dart 3.11.0. Page last updated on 2025-07-03.View source orreport an issue.


[8]ページ先頭

©2009-2026 Movatter.jp