Movatterモバイル変換


[0]ホーム

URL:


D Logo
Menu
Search

Library Reference

version 2.112.0

overview

Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page.Requires a signed-in GitHub account. This works well for small changes.If you'd like to make larger changes you may want to consider usinga local clone.

std.sumtype

SumType is a generic discriminated union implementation that usesdesign-by-introspection to generate safe and efficient code. Its featuresinclude:
  • Pattern matching.
  • Support for self-referential types.
  • Full attribute correctness (pure,@safe,@nogc, andnothrow are inferred whenever possible).
  • A type-safe and memory-safe API compatible with DIP 1000 (scope).
  • No dependency on runtime type information (TypeInfo).
  • Compatibility with BetterC.

List of examples

License:
Boost License 1.0
Authors:
Paul Backus

Sourcestd/sumtype.d

Examples:

Basic usage

import std.math.operations : isClose;struct Fahrenheit {double value; }struct Celsius {double value; }struct Kelvin {double value; }alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin);// Construct from any of the member types.Temperature t1 = Fahrenheit(98.6);Temperature t2 = Celsius(100);Temperature t3 = Kelvin(273);// Use pattern matching to access the value.Fahrenheit toFahrenheit(Temperature t){return Fahrenheit(        t.match!(            (Fahrenheit f) => f.value,            (Celsius c) => c.value * 9.0/5 + 32,            (Kelvin k) => k.value * 9.0/5 - 459.4        )    );}assert(toFahrenheit(t1).value.isClose(98.6));assert(toFahrenheit(t2).value.isClose(212));assert(toFahrenheit(t3).value.isClose(32));// Use ref to modify the value in place.void freeze(ref Temperature t){    t.match!(        (ref Fahrenheit f) => f.value = 32,        (ref Celsius c) => c.value = 0,        (ref Kelvin k) => k.value = 273    );}freeze(t1);assert(toFahrenheit(t1).value.isClose(32));// Use a catch-all handler to give a default result.bool isFahrenheit(Temperature t){return t.match!(        (Fahrenheit f) =>true,        _ =>false    );}assert(isFahrenheit(t1));assert(!isFahrenheit(t2));assert(!isFahrenheit(t3));
Examples:

Matching with an overload set

Instead of writingmatch handlers inline as lambdas, you can write them as overloads of a function. Analias can be used to create an additional overload for theSumType itself.
For example, with this overload set:
string handle(int n) {return"got an int"; }string handle(string s) {return"got a string"; }string handle(double d) {return"got a double"; }alias handle = match!handle;
Usage would look like this:
alias ExampleSumType = SumType!(int, string,double);ExampleSumType a = 123;ExampleSumType b ="hello";ExampleSumType c = 3.14;writeln(a.handle);// "got an int"writeln(b.handle);// "got a string"writeln(c.handle);// "got a double"
Examples:

Recursive SumTypes

This example makes use of the special placeholder typeThis to define arecursive data type: anabstract syntax tree for representing simple arithmetic expressions.
import std.functional : partial;import std.traits : EnumMembers;import std.typecons : Tuple;enum Op : string{    Plus  ="+",    Minus ="-",    Times ="*",    Div   ="/"}// An expression is either//  - a number,//  - a variable, or//  - a binary operation combining two sub-expressions.alias Expr = SumType!(double,    string,    Tuple!(Op,"op", This*,"lhs", This*,"rhs"));// Shorthand for Tuple!(Op, "op", Expr*, "lhs", Expr*, "rhs"),// the Tuple type above with Expr substituted for This.alias BinOp = Expr.Types[2];// Factory function for number expressionsExpr* num(double value){returnnew Expr(value);}// Factory function for variable expressionsExpr* var(string name){returnnew Expr(name);}// Factory function for binary operation expressionsExpr* binOp(Op op, Expr* lhs, Expr* rhs){returnnew Expr(BinOp(op, lhs, rhs));}// Convenience wrappers for creating BinOp expressionsalias sum  = partial!(binOp, Op.Plus);alias diff = partial!(binOp, Op.Minus);alias prod = partial!(binOp, Op.Times);alias quot = partial!(binOp, Op.Div);// Evaluate expr, looking up variables in envdouble eval(Expr expr,double[string] env){return expr.match!(        (double num) => num,        (string var) => env[var],        (BinOp bop)        {double lhs = eval(*bop.lhs, env);double rhs = eval(*bop.rhs, env);finalswitch (bop.op)            {staticforeach (op; EnumMembers!Op)                {case op:returnmixin("lhs" ~ op ~"rhs");                }            }        }    );}// Return a "pretty-printed" representation of exprstring pprint(Expr expr){import std.format : format;return expr.match!(        (double num) =>"%g".format(num),        (string var) => var,        (BinOp bop) =>"(%s %s %s)".format(            pprint(*bop.lhs),cast(string) bop.op,            pprint(*bop.rhs)        )    );}Expr* myExpr = sum(var("a"), prod(num(2), var("b")));double[string] myEnv = ["a":3,"b":4,"c":7];writeln(eval(*myExpr, myEnv));// 11writeln(pprint(*myExpr));// "(a + (2 * b))"
structThis;
Placeholder used to refer to the enclosingSumType.
structSumType(Types...) if (is(NoDuplicates!Types == Types) && (Types.length > 0));
Atagged union that can hold a single value from any of a specified set of types.
The value in aSumType can be operated on usingpattern matching.
To avoid ambiguity, duplicate types are not allowed (but see the"basic usage" example for a workaround).
The special typeThis can be used as a placeholder to create self-referential types, just like withAlgebraic. See the"Recursive SumTypes" example for usage.
ASumType is initialized by default to hold the.init value of its first member type, just like a regular union. The version identifierSumTypeNoDefaultCtor can be used to disable this behavior.
See Also:
aliasTypes = AliasSeq!(ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType));
The types aSumType can hold.
this(Tvalue);

this(const(T)value) const;

this(immutable(T)value) immutable;

this(Value)(Valuevalue) inout
if (is(Value == DeducedParameterType!(inout(T))));
Constructs aSumType holding a specific value.
this(ref inout(SumType)other) inout;
Constructs aSumType that's a copy of anotherSumType.
ref SumTypeopAssign(Trhs);
Assigns a value to aSumType.
If any of theSumType's members other than the one being assigned to contain pointers or references, it is possible for the assignment to cause memory corruption (see the"Memory corruption" example below for an illustration of how). Therefore, such assignments are considered@system.
An individual assignment can be@trusted if the caller can guarantee that there are no outstanding references to anySumType members that contain pointers or references at the time the assignment occurs.
Examples:

Memory corruption

This example shows how assignment to aSumType can be used to cause memory corruption in@system code. In@safe code, the assignments = 123 would not be allowed.
SumType!(int*,int) s =newint;s.tryMatch!(    (refint* p) {        s = 123;// overwrites `p`return *p;// undefined behavior    });
ref SumTypeopAssign(ref SumTyperhs);
Copies the value from anotherSumType into this one.
See the value-assignment overload for details on@safety.
Copy assignment is@disabled if any ofTypes is non-copyable.
ref SumTypeopAssign(SumTyperhs);
Moves the value from anotherSumType into this one.
See the value-assignment overload for details on@safety.
boolopEquals(this This, Rhs)(auto ref Rhsrhs)
if (!is(CommonType!(This, Rhs) == void));
Compares twoSumTypes for equality.
TwoSumTypes are equal if they are the same kind ofSumType, they contain values of the same type, and those values are equal.
stringtoString(this This)();
Returns a string representation of theSumType's current value.
Not available when compiled with-betterC.
voidtoString(this This, Sink, Char)(ref Sinksink, ref const FormatSpec!Charfmt);
Handles formatted writing of theSumType's current value.
Not available when compiled with-betterC.
Parameters:
SinksinkOutput range to write to.
FormatSpec!CharfmtFormat specifier to use.
size_ttoHash() const;
Returns the hash of theSumType's current value.
Not available when compiled with-betterC.
enum boolisSumType(T);
True ifT is aSumType or implicitly converts to one, otherwise false.
Examples:
staticstruct ConvertsToSumType{    SumType!int payload;alias payloadthis;}staticstruct ContainsSumType{    SumType!int payload;}assert(isSumType!(SumType!int));assert(isSumType!ConvertsToSumType);assert(!isSumType!ContainsSumType);
templatematch(handlers...)
Calls a type-appropriate function with the value held in aSumType.
For each possible type theSumType can hold, the given handlers are checked, in order, to see whether they accept a single argument of that type. The first one that does is chosen as the match for that type. (Note that the first match may not always be the most exact match. See"Avoiding unintentional matches" for one common pitfall.)
Every type must have a matching handler, and every handler must match at least one type. This is enforced at compile time.
Handlers may be functions, delegates, or objects withopCall overloads. If a function with more than one overload is given as a handler, all of the overloads are considered as potential matches.
Templated handlers are also accepted, and will match any type for which they can beimplicitly instantiated. (Remember that afunction literal without an explicit argument type is considered a template.)
If multipleSumTypes are passed to match, their values are passed to the handlers as separate arguments, and matching is done for each possible combination of value types. See"Multiple dispatch" for an example.
Returns:
The value returned from the handler that matches the currently-held type.
See Also:
Examples:

Avoiding unintentional matches

Sometimes, implicit conversions may cause a handler to match more types than intended. The example below shows two solutions to this problem.
alias Number = SumType!(double,int);Number x;// Problem: because int implicitly converts to double, the double// handler is used for both types, and the int handler never matches.assert(!__traits(compiles,    x.match!(        (double d) =>"got double",        (int n) =>"got int"    )));// Solution 1: put the handler for the "more specialized" type (in this// case, int) before the handler for the type it converts to.assert(__traits(compiles,    x.match!(        (int n) =>"got int",        (double d) =>"got double"    )));// Solution 2: use a template that only accepts the exact type it's// supposed to match, instead of any type that implicitly converts to it.alias exactly(T,alias fun) =function (arg){staticassert(is(typeof(arg) == T));return fun(arg);};// Now, even if we put the double handler first, it will only be used for// doubles, not ints.assert(__traits(compiles,    x.match!(        exactly!(double, d =>"got double"),        exactly!(int, n =>"got int")    )));
Examples:

Multiple dispatch

Pattern matching can be performed on multipleSumTypes at once by passing handlers with multiple arguments. This usually leads to more concise code than using nested calls tomatch, as show below.
struct Point2D {double x, y; }struct Point3D {double x, y, z; }alias Point = SumType!(Point2D, Point3D);version (none){// This function works, but the code is ugly and repetitive.// It uses three separate calls to match!    @safepurenothrow @nogcbool sameDimensions(Point p1, Point p2)    {return p1.match!(            (Point2D _) => p2.match!(                (Point2D _) =>true,                _ =>false            ),            (Point3D _) => p2.match!(                (Point3D _) =>true,                _ =>false            )        );    }}// This version is much nicer.@safepurenothrow @nogcbool sameDimensions(Point p1, Point p2){alias doMatch =match!(        (Point2D _1, Point2D _2) =>true,        (Point3D _1, Point3D _2) =>true,        (_1, _2) =>false    );return doMatch(p1, p2);}Point a = Point2D(1, 2);Point b = Point2D(3, 4);Point c = Point3D(5, 6, 7);Point d = Point3D(8, 9, 0);assert( sameDimensions(a, b));assert( sameDimensions(c, d));assert(!sameDimensions(a, c));assert(!sameDimensions(d, b));
ref automatch(SumTypes...)(auto ref SumTypesargs)
if (allSatisfy!(isSumType, SumTypes) && (args.length > 0));
The actualmatch function.
Parameters:
SumTypesargsOne or moreSumType objects.
templatetryMatch(handlers...)
Attempts to call a type-appropriate function with the value held in aSumType, and throws on failure.
Matches are chosen using the same rules asmatch, but are not required to be exhaustive—in other words, a type (or combination of types) is allowed to have no matching handler. If a type without a handler is encountered at runtime, aMatchException is thrown.
Not available when compiled with-betterC.
Returns:
The value returned from the handler that matches the currently-held type, if a handler was given for that type.
Throws:
MatchException, if the currently-held type has no matching handler.
See Also:
ref autotryMatch(SumTypes...)(auto ref SumTypesargs)
if (allSatisfy!(isSumType, SumTypes) && (args.length > 0));
The actualtryMatch function.
Parameters:
SumTypesargsOne or moreSumType objects.
classMatchException:object.Exception;
Thrown bytryMatch when an unhandled type is encountered.
Not available when compiled with-betterC.
pure nothrow @nogc @safe this(stringmsg, stringfile = __FILE__, size_tline = __LINE__);
templatecanMatch(alias handler, Ts...) if (Ts.length > 0)
True ifhandler is a potential match forTs, otherwise false.
See the documentation formatch for a full explanation of how matches are chosen.
Examples:
alias handleInt = (int i) =>"got an int";assert(canMatch!(handleInt,int));assert(!canMatch!(handleInt, string));
templatehas(T)
Checks whether aSumType contains a value of a given type.
The types must match exactly, without implicit conversions.
Parameters:
Tthe type to check for.
Examples:
Basic usage
SumType!(string,double) example ="hello";assert( example.has!string);assert(!example.has!double);// If T isn't part of the SumType, has!T will always return false.assert(!example.has!int);
Examples:
With type qualifiers
alias Example = SumType!(string,double);Example m ="mutable";const Example c ="const";immutable Example i ="immutable";assert( m.has!string);assert(!m.has!(const(string)));assert(!m.has!(immutable(string)));assert(!c.has!string);assert( c.has!(const(string)));assert(!c.has!(immutable(string)));assert(!i.has!string);assert(!i.has!(const(string)));assert( i.has!(immutable(string)));
Examples:
As a predicate
import std.algorithm.iteration : filter;import std.algorithm.comparison : equal;alias Example = SumType!(string,double);auto arr = [    Example("foo"),    Example(0),    Example("bar"),    Example(1),    Example(2),    Example("baz")];auto strings = arr.filter!(has!string);auto nums = arr.filter!(has!double);assert(strings.equal([Example("foo"), Example("bar"), Example("baz")]));assert(nums.equal([Example(0), Example(1), Example(2)]));
boolhas(Self)(auto ref Selfself)
if (isSumType!Self);
The actualhas function.
Parameters:
SelfselftheSumType to check.
Returns:
true ifself contains aT, otherwise false.
templateget(T)
Accesses aSumType's value.
The value must be of the specified type. Usehas to check.
Parameters:
Tthe type of the value being accessed.
Examples:
Basic usage
SumType!(string,double) example1 ="hello";SumType!(string,double) example2 = 3.14;writeln(example1.get!string);// "hello"writeln(example2.get!double);// 3.14
Examples:
With type qualifiers
alias Example = SumType!(string,double);Example m ="mutable";const(Example) c ="const";immutable(Example) i ="immutable";writeln(m.get!string);// "mutable"writeln(c.get!(const(string)));// "const"writeln(i.get!(immutable(string)));// "immutable"
Examples:
As a predicate
import std.algorithm.iteration : map;import std.algorithm.comparison : equal;alias Example = SumType!(string,double);auto arr = [Example(0), Example(1), Example(2)];auto values = arr.map!(get!double);assert(values.equal([0, 1, 2]));
ref Tget(Self)(auto ref Selfself)
if (isSumType!Self);
The actualget function.
Parameters:
SelfselftheSumType whose value is being accessed.
Returns:
theSumType's value.
templatetryGet(T)
Attempt to access aSumType's value.
If theSumType does not contain a value of the specified type, an exception is thrown.
Parameters:
Tthe type of the value being accessed.
Examples:
Basic usage
SumType!(string,double) example ="hello";writeln(example.tryGet!string);// "hello"double result =double.nan;try    result = example.tryGet!double;catch (MatchException e)    result = 0;// Exception was thrownwriteln(result);// 0
Examples:
With type qualifiers
import std.exception : assertThrown;const(SumType!(string,double)) example ="const";// Qualifier mismatch; throws exceptionassertThrown!MatchException(example.tryGet!string);// Qualifier matches; no exceptionwriteln(example.tryGet!(const(string)));// "const"
Examples:
As a predicate
import std.algorithm.iteration : map, sum;import std.functional : pipe;import std.exception : assertThrown;alias Example = SumType!(string,double);auto arr1 = [Example(0), Example(1), Example(2)];auto arr2 = [Example("foo"), Example("bar"), Example("baz")];alias trySum = pipe!(map!(tryGet!double), sum);writeln(trySum(arr1));// 0 + 1 + 2assertThrown!MatchException(trySum(arr2));
ref TtryGet(Self)(auto ref Selfself)
if (isSumType!Self);
The actualtryGet function.
Parameters:
SelfselftheSumType whose value is being accessed.
Throws:
MatchException if the value does not have the expected type.
Returns:
theSumType's value.
Copyright © 1999-2026 by theD Language Foundation | Page generated byDdoc on Sat Feb 21 04:08:08 2026

[8]ページ先頭

©2009-2026 Movatter.jp