関数パラメーターの匿名構造体タイプ

Dec 23 2020

Typescriptでは、これを行うことができます:

function foo(param: { a: string, b: number }) { }

次のように、パラメータ型を名前付き型として明示的に宣言せずに、オブジェクトを取り込む関数を宣言するには、次のようにします。

interface Parameter {
    a: string;
    b: number;
}

function foo(param: Parameter) {}

Rustでこれを行う方法はありますか、それともパラメータ型を名前付き型として明示的に宣言する必要がありますか?

回答

3 Natrix Dec 24 2020 at 05:03

Rustには、タプル、配列、および構造体の関数パラメーターのパターン分解が次のようにあります。

fn f((a, b): (u32, i32), [x, y, z]: [String; 3]) { }
struct A { a: u32, b: String }
fn g(A { a, b }: A) { }

しかし、オブジェクトは単にrustに存在しないため、名前のないタイプ/オブジェクトにはそのような構文はありません。錆がこのための構文を持っていたと想像してください:

fn f(param: {a: String, b: String}) {} // Invalid code!

誰かがその関数をどのように呼び出すでしょうか?このタイプのインスタンスを作成する方法はありません。javascript(/ typescript)では、動的型付けのためにこれが可能ですが、錆びている場合は、型を作成できるようにするために型を知っている必要があります。

関数でキーワード引数を偽造することに興味がある場合、これは役立つかもしれません:Rustでキーワードスタイルの関数引数を*偽造*する方法は?

タプルに名前を付け、パラメーターに名前を付けたい場合は、bindings_after_at次の構文を有効にする不安定な機能があります。

#![feature(bindings_after_at)]
fn f(my_tuple @ (a, b): (u32, u32)) {
    println!("this: {:?}", my_tuple);
    println!("is the same as: {:?}", (a, b));
}
// or this
fn g(arr @ [.., tail] : [u32; 5]) {
    println!("this: {}", arr[4]);
    println!("is the same as: {}", tail);
}
2 IbraheemAhmed Dec 24 2020 at 03:51

タプルを使用できます。

fn foo(param: (String, usize)) {
    let a: String = param.0;
    let b: usize = param.1;
}

構造体のような名前付きフィールドを持つのではなく、タプル値にインデックスが付けられます。タプルを破棄すると、値を追跡するのが少し簡単になります。

fn foo((a, b): (String, usize)) {
    // you can now access `a` and `b` here
}
2 AngelicosPhosphoros Dec 24 2020 at 19:11

Rustには記名型システムがあり、コードは構造型システムの例であるため、Rustではそのようなことはできません。あなたはウィキペディアでそれらについて読むことができます:https://en.wikipedia.org/wiki/Nominal_type_system https://en.wikipedia.org/wiki/Structural_type_system

構造型システムでは、型はフィールドのセットであり、名前と定義は関係ありません。対照的に、記名的型システムは、宣言が異なるが同じフィールドのセットを持つ2つの型を異なるものとして扱います(つまり、型の名前は内容よりも重要です)。

Rustは、ストリッカーであり、プログラムの一部のプロパティをタイプレベルで適用できるため、名目上選択されています。この例を考えてみましょう。

struct Employee(String);
struct Customer(String);

fn handle_order(employee: Employee, customer: Customer){}

プログラマーがミスをして、のように呼んだ場合handle_order(customer, employee)、それは構造型の言語では気付かれないが、記名的型付けではコンパイルエラーを引き起こすミスです。

また、プログラマーが型の定義を変更する必要がある場合もありますEmployee。たとえば、にフィールドを追加します。このような場合、Employeeのすべての使用が修正されたときにリファクタリングが行われることを確認できます。構造型を使用するプログラムでは、代わりにCustomerを送信するコードが存在する可能性があるため、構造型プログラムのリファクタリングは少し難しくなります。

Rustでの記名的型付けのもう1つの有名な例は、ライフタイムです。定義された型が同じで有効期間が異なる型の変数は、実際には異なる名義型を持っています。そして、すべてのRustsの安全性はこれに基づいています。

Typescriptは、JavaScriptにマッピングする方が簡単なため、構造型を使用します。