struct and record
Forms that compile (34)
Section titled “Forms that compile (34)”| Syntax | Description |
|---|---|
struct Point { public int X; } | Field |
public Point(int x) | Constructor |
public int Twice() | Methods |
public int X { get; set; } | Properties |
public int X { get; init; } | Properties with an init accessor |
public int Twice { get { … } } | Computed property |
public static int Zero() | Static method |
public static readonly int Zero = 0; | Static readonly field |
public static readonly Point Origin = new Point(); | Static readonly field with a struct value |
struct Outer { public Inner I; } | Nested structs |
readonly struct Point | readonly struct |
ref struct Span | ref struct |
private Point held; | Holding as a field |
public Point held; | Assigning via a public field |
Point[] ps = new Point[2]; | Array element |
void Use(Point p) | Receiving as a parameter |
Point Make() | Returning as a return value |
default(Point) | Generating a default value |
public static Point operator +(Point a, Point b) | Defining a binary operator |
operator +(M x, M y) | Defining addition |
operator == / operator != | Defining equality |
operator < / operator > | Defining comparison |
operator !(M x) | Defining negation |
operator ++(M x) | Defining an increment operator |
operator <<(M x, int n) | Defining a shift operator |
operator true / operator false | Defining the true / false operators |
public class Holder { … } | Declaring your own reference type |
record Tag(int N, string S); | Declaring with positional parameters |
t with { N = 2 } | with expression |
a == b | Comparison as a value |
(int n, int m) = t; | Deconstruction |
public int Twice() | Methods on a record |
record Leaf(int N) : Base; | Inheriting a base record |
record Leaf(int N, int M) : Base(N); | Inheriting a base with positional parameters |
Forms that don’t compile (7)
Section titled “Forms that don’t compile (7)”| Syntax | Description | Error | Reason | Instead |
|---|---|---|---|---|
public void Bump() { X++; } | A method that mutates this | TUKI0001 | not yet | Return a new value instead |
public static Point Current = new Point(); | A mutable static field | TUKI0001 | by design | Make it static readonly (put values that change in a Behaviour field) |
record Leaf(int A, int M) : Base(A); | Pass a differently named parameter to the base | TUKI0001 | not yet | Match the base parameter’s name (Base(N)) |
public int Twice { get { … } set { … } } | A mutable computed property | TUKI0001 | not yet | Make it get-only, or use a method (it’s copied as a value, so you can’t write it back) |
new Holder()(class に対して) | Instantiate a reference type you defined yourself | TUKI0001 | runtime | Make it a struct / record (treated as a value) |
h.V = 1;(class の値に対して) | Write to a field of a reference type you defined yourself | TUKI0001 | runtime | Same as above |
Holder.Make()(class の静的メソッド) | Call a static method of a reference type you defined yourself | TUKI0001 | runtime | Make it a Behaviour method, or use a struct |
When inheriting a base with positional parameters, you can only pass the base a parameter with a matching name. record Leaf(int N, int M) : Base(N); compiles, but record Leaf(int A, int M) : Base(A); does not. A derived value lays the base’s fields and its own fields out flat, and construction assigns each one to its place by name. |
Declaration and contents
Section titled “Declaration and contents”using UnityEngine;using Tsukimi;
public struct Point{ public int X; public int Y;}
public class SrDeclareFields : TsukimiBehaviour{ void Start() { Point p = new Point(); p.X = 1; Debug.Log(p.X + p.Y); // => 1 }}Constructor
Section titled “Constructor”using UnityEngine;using Tsukimi;
public struct Point{ public int X; public Point(int x) { X = x; }}
public class SrConstructor : TsukimiBehaviour{ void Start() { Point p = new Point(3); Debug.Log(p.X); // => 3 }}Methods
Section titled “Methods”You can write methods. You can’t write a method that mutates this (Forms that don’t compile).
using UnityEngine;using Tsukimi;
public struct Point{ public int X; public int Twice() { return X * 2; }}
public class SrMethod : TsukimiBehaviour{ void Start() { Point p = new Point(); p.X = 2; Debug.Log(p.Twice()); // => 4 }}Properties
Section titled “Properties”using UnityEngine;using Tsukimi;
public struct Point{ public int X { get; set; }}
public class SrProperty : TsukimiBehaviour{ void Start() { Point p = new Point(); p.X = 1; Debug.Log(p.X); // => 1 }}Properties with an init accessor
Section titled “Properties with an init accessor”using UnityEngine;using Tsukimi;
public struct Point{ public int X { get; init; }}
public class SrInitAccessor : TsukimiBehaviour{ void Start() { Point p = new Point { X = 1 }; Debug.Log(p.X); // => 1 }}Computed property
Section titled “Computed property”You can write get only. You can’t write set (Forms that don’t compile).
using UnityEngine;using Tsukimi;
public struct Point{ public int X; public int Twice { get { return X * 2; } }}
public class R_cps : TsukimiBehaviour{ void Start() { Point p = new Point(); p.X = 2; Debug.Log(p.Twice); // => 4 }}Static method
Section titled “Static method”using UnityEngine;using Tsukimi;
public struct Point{ public static int Zero() { return 0; }}
public class SrStaticMethod : TsukimiBehaviour{ void Start() { Debug.Log(Point.Zero()); // => 0 }}Static readonly field
Section titled “Static readonly field”using UnityEngine;using Tsukimi;
public struct Point{ public int X; public static readonly int Zero = 0;}
public class SrStaticReadonlyPrimitive : TsukimiBehaviour{ void Start() { Debug.Log(Point.Zero); // => 0 }}Static readonly field with a struct value
Section titled “Static readonly field with a struct value”It can also hold a value of a struct or record you declared yourself. You can’t write a mutable static field (Forms that don’t compile).
using UnityEngine;using Tsukimi;
public struct Point{ public int X; public static readonly Point Origin = new Point();}
public class R_srsv : TsukimiBehaviour{ void Start() { Point p = Point.Origin; Debug.Log(p.X); // => 0 }}Nested structs
Section titled “Nested structs”A struct field can hold another struct.
using UnityEngine;using Tsukimi;
public struct Inner{ public int V;}
public struct Outer{ public Inner I;}
public class SrNested : TsukimiBehaviour{ void Start() { Outer o = new Outer(); o.I.V = 1; Debug.Log(o.I.V); // => 1 }}readonly struct
Section titled “readonly struct”using UnityEngine;using Tsukimi;
public readonly struct Point{ public readonly int X; public Point(int x) { X = x; }}
public class SrReadonlyStruct : TsukimiBehaviour{ void Start() { Point p = new Point(1); Debug.Log(p.X); // => 1 }}ref struct
Section titled “ref struct”A type declared as ref struct can also be created and used as a value.
using UnityEngine;using Tsukimi;
public ref struct Span{ public int X;}
public class SrRefStruct : TsukimiBehaviour{ void Start() { Span s = new Span(); s.X = 1; Debug.Log(s.X); // => 1 }}Storage
Section titled “Storage”Holding as a field
Section titled “Holding as a field”You can hold it as a Behaviour field.
using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrField : TsukimiBehaviour{ private Point held;
void Start() { held.X = 1; Debug.Log(held.X); // => 1 }}Assigning via a public field
Section titled “Assigning via a public field”Make it public and you can set the value from the inspector.
using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrPublicField : TsukimiBehaviour{ public Point held;
void Start() { Debug.Log(held.X); // => 0 }}Array element
Section titled “Array element”using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrArray : TsukimiBehaviour{ void Start() { Point[] ps = new Point[2]; ps[0].X = 1; Debug.Log(ps[0].X); // => 1 }}Receiving as a parameter
Section titled “Receiving as a parameter”A copy is passed as the argument, so changes made by the callee don’t affect the caller’s value.
using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrParameter : TsukimiBehaviour{ void Start() { Use(new Point()); }
private void Use(Point p) { Debug.Log(p.X); // => 0 }}Returning as a return value
Section titled “Returning as a return value”using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrReturnValue : TsukimiBehaviour{ void Start() { Point p = Make(); Debug.Log(p.X); // => 0 }
private Point Make() { return new Point(); }}Generating a default value
Section titled “Generating a default value”using UnityEngine;using Tsukimi;
public struct Point{ public int X;}
public class SrDefaultValue : TsukimiBehaviour{ void Start() { Point p = default(Point); Debug.Log(p.X); // => 0 }}Defining operators
Section titled “Defining operators”Defining a binary operator
Section titled “Defining a binary operator”using UnityEngine;using Tsukimi;
public struct Point{ public int X; public static Point operator +(Point a, Point b) { Point r = new Point(); r.X = a.X + b.X; return r; }}
public class SrOperator : TsukimiBehaviour{ void Start() { Point a = new Point(); Point b = new Point(); Point c = a + b; Debug.Log(c.X); // => 0 }}Defining addition
Section titled “Defining addition”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static M operator +(M x, M y) { return new M(x.V + y.V); }}public class OpBinAdd : TsukimiBehaviour{ void Start() { M a = new M(1); M b = a + a; Debug.Log(b.V); // => 2 }}Defining equality
Section titled “Defining equality”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static bool operator ==(M x, M y) { return x.V == y.V; } public static bool operator !=(M x, M y) { return x.V != y.V; } public override bool Equals(object o) { return false; } public override int GetHashCode() { return 0; }}public class OpEqPair : TsukimiBehaviour{ void Start() { M a = new M(1); Debug.Log(a == a); // => true }}Defining comparison
Section titled “Defining comparison”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static bool operator <(M x, M y) { return x.V < y.V; } public static bool operator >(M x, M y) { return x.V > y.V; }}public class OpCmpPair : TsukimiBehaviour{ void Start() { M a = new M(1); Debug.Log(a < a); // => false }}Defining negation
Section titled “Defining negation”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static M operator !(M x) { return x; }}public class OpNot : TsukimiBehaviour{ void Start() { M a = new M(1); M b = !a; Debug.Log(b.V); // => 1 }}Defining an increment operator
Section titled “Defining an increment operator”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static M operator ++(M x) { return new M(x.V + 1); }}public class OpInc : TsukimiBehaviour{ void Start() { M a = new M(1); a++; Debug.Log(a.V); // => 2 }}Defining a shift operator
Section titled “Defining a shift operator”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static M operator <<(M x, int n) { return x; }}public class OpShift : TsukimiBehaviour{ void Start() { M a = new M(1); M b = a << 1; Debug.Log(b.V); // => 1 }}Defining the true / false operators
Section titled “Defining the true / false operators”using UnityEngine;using Tsukimi;
public struct M { public float V; public M(float v) { V = v; } public static bool operator true(M x) { return x.V > 0; } public static bool operator false(M x) { return x.V <= 0; }}public class OpTrueFalse : TsukimiBehaviour{ void Start() { M a = new M(1); if (a) { Debug.Log(1); } // => 1 }}class (declaration only)
Section titled “class (declaration only)”Declaring your own reference type
Section titled “Declaring your own reference type”The declaration itself compiles, but using it is rejected (Forms that don’t compile). struct and record work.
using UnityEngine;using Tsukimi;
public class Holder { public int V; }public class C2Decl : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 }}record
Section titled “record”Declaring with positional parameters
Section titled “Declaring with positional parameters”using UnityEngine;using Tsukimi;
public record Tag(int N, string S);
public class SrRecordPositional : TsukimiBehaviour{ void Start() { Tag t = new Tag(1, "a"); Debug.Log(t.N); // => 1 }}with expression
Section titled “with expression”using UnityEngine;using Tsukimi;
public record Tag(int N);
public class SrRecordWith : TsukimiBehaviour{ void Start() { Tag t = new Tag(1); Tag u = t with { N = 2 }; Debug.Log(u.N); // => 2 }}Comparison as a value
Section titled “Comparison as a value”using UnityEngine;using Tsukimi;
public record Tag(int N);
public class SrRecordEquality : TsukimiBehaviour{ void Start() { Tag a = new Tag(1); Tag b = new Tag(1); Debug.Log(a == b); // => true }}Deconstruction
Section titled “Deconstruction”using UnityEngine;using Tsukimi;
public record Tag(int N, int M);
public class SrRecordDeconstruct : TsukimiBehaviour{ void Start() { Tag t = new Tag(1, 2); (int n, int m) = t; Debug.Log(n + m); // => 3 }}Methods on a record
Section titled “Methods on a record”using UnityEngine;using Tsukimi;
public record Tag(int N){ public int Twice() { return N * 2; }}
public class SrRecordMethod : TsukimiBehaviour{ void Start() { Tag t = new Tag(2); Debug.Log(t.Twice()); // => 4 }}Inheriting a base record
Section titled “Inheriting a base record”using UnityEngine;using Tsukimi;
public abstract record Base;public record Leaf(int N, int M) : Base;
public class SrRecordInherit : TsukimiBehaviour{ void Start() { Leaf l = new Leaf(1, 2); Debug.Log(l.N + l.M); // => 3 }}Inheriting a base with positional parameters
Section titled “Inheriting a base with positional parameters”You can also inherit a base that has positional parameters. You can only pass the base a parameter with the same name (Forms that don’t compile).
using UnityEngine;using Tsukimi;
public abstract record Base(int N);public record Leaf(int N, int M) : Base(N);
public class R_recpos : TsukimiBehaviour{ void Start() { Leaf l = new Leaf(1, 2); Debug.Log(l.M); // => 2 }}