null と参照
書ける形(16)
Section titled “書ける形(16)”| 書き方 | 説明 |
|---|---|
string s = null; | 参照型への代入 |
new string[4] | 生成した直後の配列の要素 |
new int[4][] | 生成した直後の内側の配列 |
buffer == null | null との比較 |
s is null | null との照合 |
other != null | インタフェースの値との比較 |
s ?? "x" | null なら別の値 |
s ??= "x" | null なら代入 |
target?.name | null なら呼ばない |
target?.Rotate(...) | null なら呼ばない(戻り値なし) |
#nullable enable | 検査の有効化 |
string? s | null になりうる型 |
#nullable disable | 検査の無効化 |
s! | null でない扱い |
if (s != null) { s.Length } | 確かめたあとの扱い |
where T : notnull | null にならない型への限定 |
書けない形(4)
Section titled “書けない形(4)”| 書き方 | 説明 | エラー | 理由 | 代わりに |
|---|---|---|---|---|
c as Transform | 変換できなければ null にする | TUKI0001 | 未実装 | 型パターン(c is Transform t)で受ける |
a?[0] | 配列が null なら要素を読まない | TUKI0001 | 環境 | if (a != null) で囲む |
IShape s = new Box(); s == null | 値型に付けたインタフェースを null と比べる | TUKI0001 | 設計 | 値型は null にならない。Behaviour に付けたものなら比べられる |
Point p = new Point(); p == null | struct を null と比べる | CS0019 | 設計 | 値型は null にならない |
null の参照のメンバを呼んだり、null の配列の要素を読んだりすると、そのイベントはそこで止まります。エラーは実行環境が出します。 例外の仕組みが無いので、捕まえて続きを走らせることはできません。
null の出どころ
Section titled “null の出どころ”参照型のフィールドと配列の要素は、値を入れるまで null です。初期化子を書かなければ、最初から null が入っています。
参照型への代入
Section titled “参照型への代入”using UnityEngine;using Tsukimi;
public class CvNullLiteral : TsukimiBehaviour{ void Start() { string s = null; Debug.Log(s == null); // => true }}生成した直後の配列の要素
Section titled “生成した直後の配列の要素”using UnityEngine;using Tsukimi;
public class ArraysElementReferenceType : TsukimiBehaviour{ private string[] names;
void Start() { names = new string[4]; Debug.Log(names[0] == null); // => true names[0] = "hello"; Debug.Log(names[0]); // => "hello" }}生成した直後の内側の配列
Section titled “生成した直後の内側の配列”using UnityEngine;using Tsukimi;
public class ArraysDeclareJagged : TsukimiBehaviour{ private int[][] grid;
void Start() { grid = new int[4][]; Debug.Log(grid[0] == null); // => true grid[0] = new int[4]; grid[0][0] = 1; Debug.Log(grid[0][0]); // => 1 }}null の判定
Section titled “null の判定”null かどうかは、参照型の値に対してだけ調べられます。値型は null を取らないので、比較そのものが書けません。
null との比較
Section titled “null との比較”using UnityEngine;using Tsukimi;
public class ArraysCompareToNull : TsukimiBehaviour{ private int[] buffer;
void Start() { Debug.Log(buffer == null); // => true if (buffer == null) { buffer = new int[4]; } Debug.Log(buffer.Length); // => 4 }}null との照合
Section titled “null との照合”== null と同じ判定を、パターンとして書く形です(パターン)。
using UnityEngine;using Tsukimi;
public class PtConstNull : TsukimiBehaviour{ void Start() { string s = null; if (s is null) { Debug.Log(1); } // => 1 }}インタフェースの値との比較
Section titled “インタフェースの値との比較”null と比べられるのは、Behaviour に付けたインタフェースだけです。値型に付けたインタフェースは、値型と同じく null を取らないので比べられません。
using UnityEngine;using Tsukimi;
public interface IGadget{ void Tick();}
public class IfaceCompareNull : TsukimiBehaviour, IGadget{ public IGadget other;
public void Tick() { }
void Start() { Debug.Log(other == null); // => true if (other != null) { other.Tick(); } }}null を避ける書き方
Section titled “null を避ける書き方”null のときのふるまいを、if で囲まずに式の中へ書く形です。
null なら別の値
Section titled “null なら別の値”using UnityEngine;using Tsukimi;
public class ExpressionsNullCoalesce : TsukimiBehaviour{ void Start() { string s = null; string r = s ?? "x"; Debug.Log(r); // => "x" }}null なら代入
Section titled “null なら代入”using UnityEngine;using Tsukimi;
public class ExpressionsNullCoalesceAssign : TsukimiBehaviour{ void Start() { string s = null; s ??= "x"; Debug.Log(s); // => "x" }}null なら呼ばない
Section titled “null なら呼ばない”左が null のときは、その先の呼び出しをせずに、式全体が null になります。編集画面から差し込んでいない公開フィールドは null なので、この例の s は null です。
using UnityEngine;using Tsukimi;
public class ExpressionsNullConditionalReference : TsukimiBehaviour{ public Transform target;
void Start() { string s = target?.name; Debug.Log(s); // => null }}null なら呼ばない(戻り値なし)
Section titled “null なら呼ばない(戻り値なし)”using UnityEngine;using Tsukimi;
public class ExpressionsNullConditionalVoid : TsukimiBehaviour{ public Transform target;
void Start() { target?.Rotate(Vector3.up); }}null 安全
Section titled “null 安全”null 安全は、参照型を「null になりうる型(string?)」と「ならない型(string)」に分けて、
コンパイラが値の流れを追う仕組みです。null になりうる値を確かめずに使うと、コンパイラは
TUKI0201 を出してそこで止まります。C# のコンパイラは同じ形を警告として報告しますが、
この言語ではエラーになり、コンパイルが通りません。
検査は既定では効きません。#nullable enable と書いた行から先だけで効きます。
効くのはコンパイルの時だけです。できあがるプログラムに検査は残らないので、実行時に null で 止まることは防げません。
検査の有効化
Section titled “検査の有効化”#nullable enableusing UnityEngine;using Tsukimi;
public class PreNullableEnable : TsukimiBehaviour{ void Start() { string s = "a"; Debug.Log(s.Length); // => 1 }}#nullable enableusing UnityEngine;using Tsukimi;
public class R_nrt_assign : TsukimiBehaviour{ void Start() { string s = null; Debug.Log(s); }}null になりうる型
Section titled “null になりうる型”型に ? を付けると、null が入りうる値として扱われます。付けなければ、null は入らないものとして扱われます。
using UnityEngine;using Tsukimi;
public class NrAnnot : TsukimiBehaviour{ void Start() { #nullable enable string? s = null; Debug.Log(s == null); // => true }}#nullable enableusing UnityEngine;using Tsukimi;
public class R_nrt_deref : TsukimiBehaviour{ void Start() { string? s = null; Debug.Log(s.Length); }}検査の無効化
Section titled “検査の無効化”#nullable enableusing UnityEngine;using Tsukimi;
public class NrDisable : TsukimiBehaviour{ void Start() { #nullable disable string s = null; Debug.Log(s == null); // => true }}#nullable enableusing UnityEngine;using Tsukimi;
public class R_nrt_no_disable : TsukimiBehaviour{ void Start() { string s = null; Debug.Log(s == null); }}null でない扱い
Section titled “null でない扱い”! を付けると、null になりうる値を ? の無い型へそのまま渡せます。検査が通るだけで値は変わらないので、実際に null の値のメンバを呼べば、実行時にそこで止まります。
#nullable enableusing UnityEngine;using Tsukimi;
public class PeNullForgiving : TsukimiBehaviour{ void Start() { string? s = Get(); string t = s!; Debug.Log(t); // => "a" }
private string? Get() { return "a"; }}#nullable enableusing UnityEngine;using Tsukimi;
public class R_nrt_no_bang : TsukimiBehaviour{ void Start() { string? s = Get(); string t = s; Debug.Log(t); }
private string? Get() { return "a"; }}確かめたあとの扱い
Section titled “確かめたあとの扱い”#nullable enableusing UnityEngine;using Tsukimi;
public class NullNarrowing : TsukimiBehaviour{ void Start() { string? s = Get(); if (s != null) { Debug.Log(s.Length); } // => 2 }
private string? Get() { return "ab"; }}#nullable enableusing UnityEngine;using Tsukimi;
public class R_nrt_no_check : TsukimiBehaviour{ void Start() { string? s = Get(); Debug.Log(s.Length); }
private string? Get() { return "ab"; }}null にならない型への限定
Section titled “null にならない型への限定”using UnityEngine;using Tsukimi;
public class GcNotNull : TsukimiBehaviour{ void Start() { Debug.Log(Take<int>(1)); // => 1 }
private int Take<T>(T v) where T : notnull { return 1; }}