跳转到内容

extern

此内容尚不支持你的语言。

extern は、Unity、VRChat、CLR など Sobakasu の外側で提供される型や関数を Sobakasu から利用するための仕組みです。

通常のアプリケーションコードから外部 API を直接呼ぶこともできますが、標準ライブラリでは外部 API を Sobakasu の型や関数としてまとめてから公開します。

Sobakasu の通常の修飾名と、CLR など外部 API 側の名前では区切り方が異なります。

Sobakasu の修飾名: foo::Bar::baz
CLR の型名: UnityEngine.GameObject
CLR の入れ子型: Namespace.Outer+Inner

Sobakasu の修飾名では :: を使いますが、extern で CLR の型やメンバーを指定するときは、外部 API 側の名前をそのまま使うため . を使用します。

CLR の入れ子型では + が使われることがあります。

外部 API 名の中を :: で区切ることはできず、使用するとコンパイルエラーになります。

外部の型を Sobakasu の型として使う

Section titled “外部の型を Sobakasu の型として使う”

type ... = extern ...; を使うと、外部の型に対応する Sobakasu の型を宣言できます。

public type GameObject = extern UnityEngine.GameObject;

この例では、Sobakasu の GameObject が外部の UnityEngine.GameObject に対応します。

これは別の Sobakasu 型に単なる別名を付ける機能ではありません。外部に実在する型との対応付けです。

外部型が構造体や列挙型として扱われる場合は、struct や enum として対応付けられます。

public struct VectorLike = extern Runtime.VectorLike {
x: f32 = extern x,
y: f32 = extern y,
}
public enum Direction = extern Runtime.Direction {
Left = extern Left,
Right = extern Right,
}

外部に存在しない型やメンバー、Udon から利用できない API を指定するとコンパイルエラーになります。

外部型に対する関数は implementation にまとめられます。

public implementation GameObject = extern UnityEngine.GameObject {
function get_name(self) -> string
= extern UnityEngine.GameObject.get_name(self);
}

実際に指定できる外部名は、VRChat/Udon が公開している API によって決まります。

関数本体の代わりに = extern ...; と書くと、Sobakasu の関数を外部 API に対応付けられます。

function log(value: object)
= extern UnityEngine.Debug.Log(value);

利用側は log(...) という Sobakasu の関数名だけを使えるため、外部 API の長い名前を毎回書く必要がありません。

外部 API には、一つの戻り値だけでなく ref や out を使って複数の値を返すものがあります。

  • ref — 呼び出す前の値を入力として渡し、呼び出し後の値も受け取る
  • out — 呼び出し後の値を受け取る

Sobakasu では、これらの複数の出力を通常の戻り値として受け取れるようにし、必要な場合はタプルとしてまとめます。

function update(value: i32) -> (bool, i32, string)
= extern External.Api.Update(ref i32 value, out string message);

外部 API は null を返すことがありますが、Sobakasu の通常の値では null を使用しません。

maybe extern を使う外部関数では、外部 API から返された null を Maybe<T> の「値なし」として扱えます。

function find(name: string) -> Maybe<GameObject>
= maybe extern UnityEngine.GameObject.Find(name);

これにより、Sobakasu 側では null ではなく Maybe<T> として値の有無を扱えます。

標準ライブラリでは、参照型の戻り値と out は原則 Maybe<T> として公開されます。対象の Unity / VRChat SDK で正常終了時に必ず値が返ることを確認した API は、通常の T として公開される場合があります。たとえば BitConverter の get_bytes は [u8] を直接返します。実際の戻り値の型は、その関数の宣言を確認してください。成功時だけ値が存在する API や、保証を確認できない API は Maybe<T> のままです。

外部 API が返す配列も、null になり得る場合は Maybe<[T]> として受け取れます。Maybe<[T]> は配列参照そのものの有無を表し、配列要素ごとの Maybe 化を意味しません。値の有効性は、返された配列参照を object として確認します。この受け渡しは参照変換であり、配列の各要素をボクシングする処理ではありません。

外部 API で使用される IEnumerator<VRCConstraintSource> などの具体的なジェネリック参照型も、Udon で値を保持できる場合は Maybe<T> の値にできます。一方、Sobakasu のユーザー定義 struct や enum、それらを要素とする配列を、単一の外部オブジェクトとして object 引数へ渡すことはできません。

配列を外部 API と受け渡せることと、その配列を Sobakasu で生成したり添字で操作したりできることは別です。生成や添字アクセスには、対応する操作が Udon に公開されている必要があります。

外部 API の out が null になり得る場合には、対応する場所で maybe out も使用されます。

外部 API をその場で直接呼び出すこともできます。

extern UnityEngine.Debug.Log("hello");

同じ API を複数の場所から利用する場合は、function や implementation としてまとめると、利用側を外部 API の名前から切り離せます。

外部型に利用可能なコンストラクターがある場合は、new を使って生成できます。

new SomeType(arg)

そのコンストラクターが Udon から利用できない場合はコンパイルエラーになります。

extern の書き方が正しくても、指定した型や関数が現在の VRChat SDK から Udon 向けに公開されていなければ利用できません。

外部 API との間で値をどの形式で受け渡すかという規約を ABI と呼びます。ref / out、配列、外部型などを使う場合は、Sobakasu 側の宣言と Udon 側の ABI が一致している必要があります。

このページでは extern の書き方と意味を説明します。実際に標準ライブラリから利用できる API は 標準ライブラリリファレンス を参照してください。