サポートされている型

この章では、Candid でサポートされているすべての型をリストアップしています。 それぞれの型について、以下の情報が記載されています:

  • 型の構文と、型のテキスト表現の構文。

  • それぞれの型に対する Candid のアップグレードに関するルールは、型の サブタイプスーパータイプ によって決まります。

  • それぞれの型に対応する Rust、Motoko、Javascript の型。

既存メソッドの 返り値 の型は以前の型のサブタイプに変更できます。 既存メソッドの 引数 の型は以前の型のスーパータイプに変更できます。

このリファレンスには、それぞれの型に関連する特定のサブタイプとスーパータイプのみが記載されていることに注意してください。 どの型にも適用可能なサブタイプやスーパータイプは記載していません。 たとえば、empty は他のどの型のサブタイプにもなりうるので、このリファレンスではサブタイプとして挙げていません。 同様に、reservedopt t 型 は、任意の型のスーパータイプであるため、特定の型のスーパータイプとして挙げていません。 emptyreservedopt t 型のサブタイプ化のルールに関する詳細については、以下の節を参照してください。

text 型

text 型は、人が読めるテキストが必要な場面で使われます。より正確には、unicode の符号位置のシーケンスです(サロゲート部分を除く)。

型の構文

text

テキスト表現の構文
""
"Hello"
"Escaped characters: \n \r \t \\ \" \'"
"Unicode escapes: \u{2603} is ☃ and \u{221E} is ∞"
"Raw bytes (must be utf8): \E2\98\83 is also ☃"
対応する Motoko の型

Text

対応する Rust の型

String または &str

対応する JavaScript の値

"String"

blob 型

blob 型は、バイナリデータ(バイトのシーケンス)に用いることができます。 blob 型を用いて書かれたインターフェースは、vec nat8 を用いて書かれたインターフェースと互換性があります。

型の構文

blob

テキスト表現の構文

blob <text>

ここで、<text> は、すべての文字が UTF8 エンコーディングで表現された文字列リテラルと任意のバイトシーケンス("\CA\FF\FE")を表します。

Text 型に関して詳しく知りたい場合は、Text 型を参照してください。

サブタイプ

vec nat8 および vec nat8 の全てのサブタイプ。

スーパータイプ

vec nat8 および vec nat8 の全てのスーパータイプ。

対応する Motoko の型

Blob

対応する Rust の型

Vec<u8> または &[u8]

対応する JavaScript の値

[ 1, 2, 3, 4, ... ]

nat 型

nat 型は、すべての(非負の)自然数を含みます。 値の大きさに制限はなく、任意の大きな数字を表すことができます。 通信時のエンコーディングは LEB128 なので、小さな数字も効率よく表現できます。

型の構文

nat

テキスト表現の構文
1234
1_000_000
0xDEAD_BEEF
スーパータイプ

int

対応する Motoko の型

Nat

対応する Rust の型

candid::Nat または u128

対応する JavaScript の値

BigInt(10000) または 10000n

int 型

int 型はすべての整数を含みます。 大きさに制限がなく、任意の大小の数値を表現することができます。 通信時のエンコーディングは SLEB128 なので、小さな数字も効率的に表現できます。

型の構文

int

テキスト表現の構文
1234
-1234
+1234
1_000_000
-1_000_000
+1_000_000
0xDEAD_BEEF
-0xDEAD_BEEF
+0xDEAD_BEEF
サブタイプ

nat

対応する Motoko の型

Int

対応する Rust の型

candid::Int または i128

対応する JavaScript の値

BigInt(-10000) または -10000n

natN 型と intN 型

nat8nat16nat32nat64int8int16int32int64 の型は、そのビット数の表現を持つ数値を表し、より低レベルなインターフェースで使用することができます。

natN の範囲は {0 …​. 2^N-1} であり、intN の範囲は -2^(N-1) …​ 2^(N-1)-1 となります。

通信時の表現は、ちょうどその長さのビット数になります。そのため、小さな値に対しては、nat64 よりも nat の方が容量の効率が良いです。

型の構文

nat8, nat16, nat32, nat64, int8, int16, int32 または int64

テキスト表現の構文

nat8, nat16, nat32, nat64nat と同じです。

int8, int16, int32, int64int と同じです。

型アノテーションを使って、異なる整数型を区別することができます。

100 : nat8
-100 : int8
(42 : nat64)
対応する Motoko の型

natN はデフォルトでは NatN に翻訳されますが、必要に応じて WordN にも翻訳されます。

intNIntN に翻訳されます。

対応する Rust の型

同サイズの符号付き整数と符号なし整数に対応します。

ビット長 符号付き 符号なし

8-bit

i8

u8

16-bit

i16

u16

32-bit

i32

u32

64-bit

i64

u64

対応する JavaScript の値

8-bit, 16-bit, 32-bit は number 型に翻訳されます。

int64nat64 は JavaScript の BigInt プリミティブに翻訳されます。

float32 型と float64 型

float32 型および float64 型は,IEEE 754 の浮動小数点数を、単精度(32ビット)および倍精度(64ビット)で表したものです。

型の構文

float32, float64

テキスト表現の構文

int と同じ構文で、次のように浮動小数点リテラルが加わります:

1245.678
+1245.678
-1_000_000.000_001
34e10
34E+10
34e-10
0xDEAD.BEEF
0xDEAD.BEEFP-10
0xDEAD.BEEFp+10
対応する Motoko の型

float64Float に対応します。

float32 は、現在、Motoko での表現はありません。float32 を使った Candid インターフェースは、Motoko のプログラムからは生成できませんし、利用することもできません。

対応する Rust の型

f32, f64

対応する JavaScript の値

float number

bool 型

bool 型は論理値を示すデータ型で、true または false の値のみを持つことができます。

型の構文

bool

テキスト表現の構文

true, false

対応する Motoko の型

Bool

対応する Rust の型

bool

対応する JavaScript の値

true, false

null 型

null 型は値 null の型であり、全ての opt t 型のサブタイプです。また、バリアントを使用して列挙型をモデル化する際に慣例的に使用されます。

型の構文

null

テキスト表現の構文

null

スーパータイプ

全ての opt t 型。

対応する Motoko の型

Null

対応する Rust の型

()

対応する JavaScript の値

null

vec t 型

vec 型はベクター(シーケンス、リスト、配列)を表します。 vec t 型の値は、t 型の 0 個以上の値のシーケンスを含みます。

型の構文

vec bool, vec nat8, vec vec text など。

テキスト表現の構文
vec {}
vec { "john@doe.com"; "john.doe@example.com" };
サブタイプ
  • tt' のサブタイプであるときはいつでも、vec tvec t' のサブタイプです。

  • blobvec nat8 のサブタイプです。

スーパータイプ
  • tt' のスーパータイプであるときはいつでも、vec tvec t' のスーパータイプです。

  • blobvec nat8 のスーパータイプです。

対応する Motoko の型

[T] となります。ここで、Motoko 型の Tt に対応しています。

対応する Rust の型

Vec<T> または &[T] となります。ここで、Rust 型の Tt に対応しています。

vec tBTreeSet または HashSet に翻訳されます。

vec record { KeyType; ValueType } は、BTreeMap または HashMap に翻訳されます。

対応する JavaScript の値

Array 例えば [ "text", "text2", …​ ]

opt t 型

opt t 型は、t 型のすべての値と、特殊な値である null を含みます。 これは、ある値が任意であることを表現するのに使われます。つまり、データは t 型の値として存在するかもしれないし、null という値として存在しないかもしれない、ということです。

opt 型は入れ子にすることができ(例:opt opt text)、値 nullopt null は別の値です。

opt 型は、Candid インターフェース のアップグレードにおいて重要な役割を果たしており、以下のような特別なサブタイプのルールを持っています。

型の構文

opt bool, opt nat8, opt opt text など。

テキスト表現の構文
null
opt true
opt 8
opt null
opt opt "test"
サブタイプ

opt を使ったサブタイプの規範的なルールは次の通りです:

  • tt' のサブタイプであるときはいつでも、opt topt t' のサブタイプです。

  • nullopt t' のサブタイプです。

  • topt t のサブタイプです(t 自体が null でない限り、opt …​ または reserved )。

加えて、アップグレードや上位のサービスに関する技術的な理由から、 every 型は opt t のサブタイプであり、型が一致しない場合には null が生成されます。ただし、ユーザーはこのルールを直接利用しないようにしてください。

スーパータイプ
  • tt' のスーパータイプであるとき、opt topt t' のスーパータイプです。

対応する Motoko の型

?T となります。ここで、Motoko 型の Tt に対応しています。

対応する Rust の型

Option<T> となります。ここで、Rust 型の Tt に対応しています。

対応する JavaScript の値

null[] に翻訳されます。

opt 8[8] に翻訳されます。

opt opt "test"[["test"]] に翻訳されます。

record { n : t, … } 型

record 型はラベル付けされた値の集まりです。例えば、以下のコードはテキストフィールドの streetcitycountry と数値フィールドの zip_code を持つ record の型に address という名前を与えています。

type address = record {
  street : text;
  city : text;
  zip_code : nat;
  country : text;
};

record 型宣言のフィールドの順序は重要ではありません。 各フィールドは異なる型を持つことができます(同じ型のみを持つことができる vector とは異なります)。 record フィールドのラベルは、以下の例のように 32 ビットの自然数にすることもできます。

type address2 = record {
  288167939 : text;
  1103114667 : text;
  220614283 : nat;
  492419670 : text;
};

実際のところテキストラベルはその ハッシュ値 として扱われますし、さらに言えば addressaddress2 は Candid にとって同じ型です。

ラベルを省略すると、Candid は自動的に順次昇順のラベルを割り当てます。この挙動により,以下のような短縮された構文になり、通常ペアやタプルを表現するのに使われます。record { text; text; opt bool } は、record { 0 : text; 1: text; 2: opt bool } と同等です。

型の構文
record {}
record { first_name : text; second_name : text }
record { "name with spaces" : nat; "unicode, too: ☃" : bool }
record { text; text; opt bool }
テキスト表現の構文
record {}
record { first_name = "John"; second_name = "Doe" }
record { "name with spaces" = 42; "unicode, too: ☃" = true }
record { "a"; "tuple"; null }
サブタイプ

record のサブタイプとは、(任意のタイプの)フィールドが追加されたり、フィールドの型がサブタイプに変更されたり、選択型のフィールドが削除されたりした record 型のことです。ただし、メソッドの返り値で選択型のフィールドを削除するのはバッドプラクティスです。フィールドの型を opt empty に変更することで、そのフィールドがもう使われていないことを示すことができます。

例えば、次のような record を返す関数があったとします:

record {
  first_name : text; middle_name : opt text; second_name : text; score : int
}

上の record は、次のような record に更新することができます:

record {
  first_name : text; middle_name : opt empty; second_name : text; score : nat; country : text
}

ここでは、middle_name フィールドを非推奨とし、score の型を変更し、country フィールドを追加しています。

スーパータイプ

record のスーパータイプとは、一部のフィールドが削除された record 型、一部のフィールドのタイプがスーパータイプに変更された record 型、または選択型のフィールドが追加された record 型のことです。

後者は、引数の record を追加フィールドで拡張することができるものです。古いインターフェースを使用しているクライアントは、 record にフィールドを含めることができず、アップグレードされたサービスで期待される null としてデコードされます。

例えば、レコード 型を期待する関数があるとします。

record { first_name : text; second_name : text; score : nat }

以下の record を受け取る関数に更新することができます。

record { first_name : text; score: int; country : opt text }
対応する Motoko の型

record 型がタプル(例えば、0 から始まる連続したラベル)を参照している場合は、Motoko のタプル型(例えば (T1, T2, T3))が使用されます。それ以外の場合は、Motoko の record ({ first_name :Text, second_name : Text }) が使用されます。

フィールド名が Motoko の予約語の場合は、アンダースコア が付加されます。つまり、record { if : bool } は、{ if_ : Bool } となります。

フィールド名が Motoko の有効な識別子でない場合は、代わりに フィールド のハッシュが使われます。例えば、record { ☃ : bool }{ 11272781 : Boolean } となります。

対応する Rust の型

derive(CandidType, Deserialize)] というトレイトを持つ、ユーザ定義の 構造体 となります。

フィールド名を変更するには、#[serde(rename = "DifferentFieldName")] 属性を使用します。

record 型がタプルの場合は、(T1, T2, T3) のようなタプル型に変換されます。

対応する JavaScript の値

record 型がタプルの場合、配列に変換されます。例えば、["Candid", 42] のようになります。

それ以外の場合は、record オブジェクトに翻訳されます。例えば、{ "first name": "Candid", age: 42 } のようになります.

フィールド名がハッシュの場合は、フィールド名として _hash_ を使用します。例えば、{ _1_: 42, "1": "test" } のようになります。

variant { n : t, … } 型

variant 型は、定義された値の組み合わせ(あるいは タグ)のうちの 1 つの値を表します。つまり、以下の variant 型は、dot、circle(半径が与えられる)、rectangle(寸法が与えられる)、吹き出し(テキストが与えられる)のいずれかです。なお、吹き出しは、ユニコードのラベル(💬)の使用が可能であることを例示しています。

type shape = variant {
  dot : null;
  circle : float64;
  rectangle : record { width : float64; height : float64 };
  "💬" : text;
};

variant 型のタグは、record 型のラベルと同様、実際には数字であり、文字列のタグはそのハッシュ値を指します。

しばしば、タグの一部(または全部)がデータを持たないことがあります。このような場合、上記の dot のように、null 型を使用するのが慣例です。実際、Candid はこのような使い方を推奨しており、variant では : null 型のアノテーションを省略することができます。つまり、

type season = variant { spring; summer; fall; winter }

は以下と等価であり、

type season = variant {
  spring : null; summer: null; fall: null; winter : null
}

となります。これは列挙を表現するのに使われます。

variant {} 型は構文上問題ありませんが、値を持っていません。値がないことを意図するのであれば、emptyの方が適切かもしれません。

型の構文
variant {}
variant { ok : nat; error : text }
variant { "name with spaces" : nat; "unicode, too: ☃" : bool }
variant { spring; summer; fall; winter }
テキスト表現の構文
variant { ok = 42 }
variant { "unicode, too: ☃" = true }
variant { fall }
サブタイプ

variant 型のサブタイプは、一部のタグを削除し、一部のタグの型をサブタイプに変更した variant 型です。

メソッドの返り値の variant に新しいタグを 追加 できるようにしたい場合、variant 自体が opt …​ でラップされていれば可能です。これには事前の計画が必要です。インターフェースを設計する際には、次のように書く代わりに:

service {
  get_member_status (member_id : nat) -> (variant {active; expired});
}

以下のように書くのが良いでしょう:

service {
  get_member_status (member_id : nat) -> (opt variant {active; expired});
}

このようにすることで、後に 名誉 会員ステータスを追加する必要が生じた場合に、ステータスのリストを拡張することができます。古いクライアントは未知のフィールドを null として受け取ります。

スーパータイプ

variant 型のスーパータイプは、タグが追加された variant です。一部のタグの型がスーパータイプに変更されている場合もあります。

対応する Motoko の型

variant 型は、以下のように Motoko の variant 型として表現されます:

type Shape = {
  #dot : ();
  #circle : Float;
  #rectangle : { width : Float; height : Float };
  #_2669435721_ : Text;
};

列挙型を variant としてモデル化する際、Candid と Motoko それぞれの慣例の対応付けを行う必要があるため、タグの型が null の場合は Motoko では () に対応することに注意してください。

対応する Rust の型

#[derive(CandidType, Deserialize)] トレイトを持つユーザー定義の enum となります。

フィールド名を変更するには、#[serde(rename = "DifferentFieldName")] 属性を使用することができます。

対応する JavaScript の値

1 つの要素を持つ record オブジェクトとなります。例えば、{ dot: null } のようになります。

フィールド名がハッシュ値の場合には、フィールド名として _hash_ を用います。例えば、{ _2669435721_: "test" } のようになります。

func (…) → (…) 型

Candid は、上位のユースケースをサポートするように設計されており、あるサービスが他のサービスやそのメソッドへの参照を受け取ったり、提供したりすることができます(例:コールバック関数)。 func 型はこの目的において中心的な役割を果たします。これは、関数の シグネチャ (引数や返り値の型、アノテーション)を示しており、この型の値は、そのシグネチャを持つ関数への参照となります。

サポートされているアノテーションは以下の通りです:

  • query は、Canister のステートを変更せず、安価なクエリコールのメカニズムを使用して呼び出すことができることを意味しています。

  • oneway は、この関数が何のレスポンスも返さないことを示します。これは、Fire and Forget シナリオ(訳註:イベントハンドラなど、非同期呼び出しで関数を投げ放す場合)を想定しています。

引数の命名について詳しく知りたい方は、引数と返り値の命名を参照してください。

型の構文
func () -> ()
func (text) -> (text)
func (dividend : nat, divisor : nat) -> (div : nat, mod : nat);
func () -> (int) query
func (func (int) -> ()) -> ()
テキスト表現の構文

現在、プリンシパルによって識別されるサービスのパブリックメソッドのみサポートされています。

func "w7x7r-cok77-xa".hello
func "w7x7r-cok77-xa"."☃"
func "aaaaa-aa".create_canister
サブタイプ

サービスのアップグレードのルールで説明されているように、以下の修正は、ある func 型をそのサブタイプに変更します:

  • 返り値の型のリストを拡張することができます。

  • 引数の型のリストを短くすることができます。

  • 引数の型のリストを、オプションの引数(opt …​ 型)で拡張することができます。

  • 既存の引数の型を スーパータイプ に変更することができます。言い換えれば、関数の型は引数の型に 反変 であるということです。

  • 既存の返り値の型をサブタイプに変更することができます。

スーパータイプ

以下の修正は、ある func 型をそのスーパータイプに変更します:

  • 返り値の型のリストを短くすることができます。

  • 返り値の型のリストはオプションの引数(opt …​ 型)で拡張することができます。

  • 引数の型のリストは拡張さすることができます。

  • 既存の引数の型を サブタイプ に変更することができます。言い換えれば、関数の型は引数の型に 反変 であるということです。

  • 既存の返り値の型をスーパータイプに変更することができます。

対応する Motoko の型

Candid の関数型は、Motoko の shared 関数型に対応しており、返り値の型は async でラップされています(oneway でアノテーションされていない限り、返り値の型は単に () となります)。引数と返り値はタプルになりますが、1 つだけ指定されている場合はタプルにならず、直接使用されます:

type F0 = func () -> ();
type F1 = func (text) -> (text);
type F2 = func (text, bool) -> () oneway;
type F3 = func (text) -> () oneway;
type F4 = func () -> (text) query;

は、Motoko では以下に対応します:

type F0 = shared () -> async ();
type F1 = shared Text -> async Text;
type F2 = shared (Text, Bool) -> ();
type F3 = shared (text) -> ();
type F4 = shared query () -> async Text;
対応する Rust の型

candid::IDLValue::Func(Principal, String) となります。詳しくは、 IDLValue を参照ください。

対応する JavaScript の値

[Principal.fromText("aaaaa-aa"), "create_canister"]

service {…} 型

サービスは、それぞれの関数(funcを使用)だけでなく、サービス全体への参照を渡したい場合があります。このような場合には、Candid の型はサービスの(完全な)インターフェースを宣言するために使うことができます。

service 型の構文に関する詳細は、Candid Service の記述を参照してください。

型の構文
service {
  add : (nat) -> ();
  subtract : (nat) -> ();
  get : () -> (int) query;
  subscribe : (func (int) -> ()) -> ();
}
テキスト表現の構文
service "w7x7r-cok77-xa"
service "zwigo-aiaaa-aaaaa-qaa3a-cai"
service "aaaaa-aa"
サブタイプ

service 型のサブタイプとは、追加のメソッドが付与されたり、既存のメソッドの型がサブタイプに変更されている service 型です。

これは、Service のアップグレード内のルールにて説明されているのと同じ原理に基づくものです。

スーパータイプ

service 型のスーパータイプとは、一部のメソッドが削除されたり、既存のメソッドの型がスーパータイプに変更されている service 型です。

対応する Motoko の型

Candid の Service 型は Motoko の actor 型に直接対応します:

actor {
  add : shared Nat -> async ()
  subtract : shared Nat -> async ();
  get : shared query () -> async Int;
  subscribe : shared (shared Int -> async ()) -> async ();
}
対応する Rust の型

candid::IDLValue::Service(Principal) に対応します。詳しくは、 IDLValue を参照してください。

対応する JavaScript の値

Principal.fromText("aaaaa-aa")

principal 型

Internet Computer では、Canister やユーザーや他のエンティティを識別するための共通の方式として、principal を使用しています。

型の構文

principal

テキスト表現の構文
principal "w7x7r-cok77-xa"
principal "zwigo-aiaaa-aaaaa-qaa3a-cai"
principal "aaaaa-aa"
対応する Motoko の型

Principal

対応する Rust の型

candid::Principal または ic_types::Principal

対応する JavaScript の値

Principal.fromText("aaaaa-aa")

reserved 型

reserved 型は、1つの(情報を持たない)値 reserved を持つ型で、他のすべての型のスーパータイプです。

メソッドの引数を削除するのに reserved 型を使用することができます。次のようなシグネチャを持つメソッドを考えてみましょう:

service {
  foo : (first_name : text, middle_name : text, last_name : text) -> ()
}

ここで、middle_name をもはや使わなくなったと仮定します。ところが、Candid はあなたが関数シグネチャを以下のように変更することを妨げません:

service {
  foo : (first_name : text, last_name : text) -> ()
}

これは非常に危険です。なぜなら、クライアントが古いインターフェースを使ってコールした場合、この関数は黙って last_name を無視し、middle_namelast_name として受け取ることになるからです。メソッドの引数名は単なる慣例であり、メソッドの引数はその位置によって識別されることを思い出してください。

代わりに、以下のようにすることができます:

service {
  foo : (first_name : text, middle_name : reserved, last_name : text) -> ()
}

これは、foo は以前は第 2 引数を使用していたものの、現在は使用していないということを示しています。

将来引数が変わることが予想される関数や、型ではなく位置でしか区別できない引数を持つ関数は、1つの record を取るように宣言するというパターンを採用することで、この落とし穴を回避することができます。 例えば以下のようになります:

service {
  foo : (record { first_name : text; middle_name : text; last_name : text}) -> ()
}

ここで、関数シグネチャを以下のように変更します:

service {
  foo : (record { first_name : text; last_name : text}) -> ()
}

これは正しく動作します。このようにすることで、削除された引数に関する記録を残す必要もありません。

一般的に、メソッドから引数を削除することは推奨されません。通常は、引数を省略した新しいメソッドを導入することが望ましいです。
型の構文

reserved

テキスト表現の構文

reserved

サブタイプ

全ての型

対応する Motoko の型

Any

対応する Rust の型

candid::Reserved

対応する JavaScript の値

任意の値

empty 型

empty 型は、値を持たない型で、他のどの型のサブタイプでもあります。

empty 型の実用的なユースケースは比較的まれです。 例えば、empty 型は、あるメソッドが「決して正常にリターンしない」ことを示すために使用することができます:

service : {
  always_fails () -> (empty)
}
型の構文

empty

テキスト表現の構文

この型には値がないため、テキスト表現はありません。

スーパータイプ

全ての型

対応する Motoko の型

None

対応する Rust の型

candid::Empty

対応する JavaScript の値

この型には値がないため、対応する JavaScript の値はありません。