Foobar
Foobar

Reputation: 8485

anonymous struct type for function parameter

In Typescript, I can do this:

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

In order to declare a function that takes in an object, without explicitly declaring the parameter type as a named type like this:

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

function foo(param: Parameter) {}

Is there a way I can do this in Rust, or do I have to explicitly declare the parameter type as a named type?

Upvotes: 5

Views: 2750

Answers (3)

Angelicos Phosphoros
Angelicos Phosphoros

Reputation: 3083

You can't do such things in Rust because it has nominal type system and your code is example of structural type systems. You can read about them in wikipedia: https://en.wikipedia.org/wiki/Nominal_type_system https://en.wikipedia.org/wiki/Structural_type_system

In structural type system, type is just set of it's fields and it's name and definition doesn't matter. In contrast, nominal type system treats 2 types with different declaration but same set of fields as different (meaning, that name of the type more important than contents).

Rust chosen nominal because it is stricker and allows to enforce some properties of program at type level. Consider this example:

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

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

If programmer made a mistake and call it like handle_order(customer, employee), it is a mistake which wouldn't be noticed in language with structural typing but would trigger compile error in nominal typing.

Also, there can be situation when programmer need to change definition of type, for example, add a field to the Employee. In such case, one can be sure that refactoring done when all uses of Employee fixed. In program with structural typing, one cannot be sure because there can be a code which sends Customer instead of and thus refactoring of structural typed programs are little harder.

Another famous example of nominal typing in Rust is the lifetimes. Variables with types with same defined type and different lifetimes actually have different nominal types. And all Rusts safety is based on this.

Typescript uses structural typing because it is easier to map it into JavaScript.

Upvotes: 2

Natrix
Natrix

Reputation: 113

Rust has pattern deconstruction for function parameters on tuples, arrays and structs like this:

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

But it has no such syntax for unnamed types / objects, since objects simply do not exist in rust. Imagine rust had a syntax for this:

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

How would someone call that function? There is no way to construct an instance of this type. In javascript (/typescript) this is possible, because of dynamic typing, but in rust you have to know a type to be able to construct it.

If you are interested into faking keyword arguments in functions, this might help: How to best *fake* keyword style function arguments in Rust?

If you want to give the tuples a name as well as having their parameters a name, there is the unstable bindings_after_at-feature enabling this syntax:

#![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);
}

Upvotes: 4

Ibraheem Ahmed
Ibraheem Ahmed

Reputation: 13618

You can use a tuple:

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

Rather than having named fields like structs, tuple values are indexed. Destructuring the tuple makes it a little easier to keep track of the values:

fn foo((a, b): (String, usize)) {
    // you can now access `a` and `b` here
}

Upvotes: 3

Related Questions