Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to destructure the `self` argument of a method?

I am trying to find a way to destructure the self argument of a method. According to a GitHub comment:

Per today's meeting, we have a different plan to make self arguments destructurable. With universal function-call syntax (UFCS #11938) there will not be any distinction between static methods and instance methods - they will both be 'associated functions'. At that point any function who's first argument is the self type will be callable with method syntax, and self, &self, and &mut self are just sugar for i.e. self: &Self, and destructuring on the self argument can be done as normal by not using the self-sugar.

I wrote the following code, but it does not work as I expected in that all three print functions can be used as a method.

struct Vector {
    x: i32,
    y: i32,
    z: i32,
}

impl Vector {
    fn print1(self: &Self) {
        println!("{} {} {}", self.x, self.y, self.z);
    }

    // destructure self argument
    fn print2(&Vector{x, y, z}: &Self) {
        println!("{} {} {}", x, y, z);
    }

    // use another name for the first argument
    fn print3(this: &Self) {
        println!("{} {} {}", this.x, this.y, this.z);
    }
}

fn main() {
    let v = Vector{x: 1, y: 2, z: 3};

    Vector::print1(&v); // work
    v.print1();         // work
    Vector::print2(&v); // work
    v.print2();         // not work
    Vector::print3(&v); // work
    v.print3();         // not work
}

print3() was just used to test if it is possible to use a name other than self for the first argument of a method.

It gives this compile error:

error: no method named `print2` found for type `Vector` in the current scope
  --> 1.rs:27:7
   |
27 |     v.print2();         // not work
   |       ^^^^^^
   |
   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: candidate #1 is defined in an impl for the type `Vector`
  --> 1.rs:12:5
   |
12 |       fn print2(&Vector{x, y, z}: &Self) {
   |  _____^ starting here...
13 | |         println!("{} {} {}", x, y, z);
14 | |     }
   | |_____^ ...ending here

error: no method named `print3` found for type `Vector` in the current scope
  --> 1.rs:29:7
   |
29 |     v.print3();         // not work
   |       ^^^^^^
   |
   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: candidate #1 is defined in an impl for the type `Vector`
  --> 1.rs:16:5
   |
16 |       fn print3(this: &Self) {
   |  _____^ starting here...
17 | |         println!("{} {} {}", this.x, this.y, this.z);
18 | |     }
   | |_____^ ...ending here

It seems that print2() and print3() are not identified as methods of Vector.

  1. How to destructure the self argument of a method?
  2. According to the comment, the name self is just sugar. Does it mean that a name other than self can be used for the first argument of a method?
like image 368
Laurence Avatar asked Apr 25 '17 06:04

Laurence


1 Answers

This was originally intended to be possible with the Universal Function Calls, but is backwards incompatible, because it would mean that fn foo(bar: &Self) would suddenly be equivalent to fn foo(self: &Self), which can break method calls due to new methods appearing suddenly.

Full rationale in this github issue comment

You can destructure the explicit self parameter with a let binding in the function body:

let &Vector { x, y, z } = self;
like image 152
oli_obk Avatar answered Sep 23 '22 16:09

oli_obk