Better feature of mut parameter in fn

Currently, mut parameter in fn is just

fn foo(mut self){}
//==
fn foo2(self){
let mut mutself=self
}

I found some situation, that a function may takes owership of a value and then return same type( or itself) back.
Then I get idea to take more use of mut param.

//fn foo(a:mut String,b:String)->i32{
fn foo(mut a:String,b:String)->i32{
    a=format!("{}, {}",a,b);
    return a.len()
}
let mut a=String::from("a");
let b=String::from("b");
let c=foo(mut a,b);//ownership is given and returned
let d=foo(b,a);//ownership of b is given but not returned 

example

/*
pub trait MapperOnce<Input>{
    type Output;
    fn map(self,value:Input)->Self::Output;
}
pub trait MapperMut<Input>{
    type Output;
    fn map(&mut self,value:Input)->Self::Output;
}
pub trait Mapper<Input>{
    type Output;
    fn map(&self,value:Input)->Self::Output;
}*/
pub trait Mapper<Input>{
    type Output;
    fn map(self,value:Input)->(Self::Output,Self);
}
pub struct AStruct(i32);
impl<'a> Mapper<i32> for &'a AStruct{
    type Output=i32;
    fn map(self,value:i32)->(i32,Self){
        (value+self.0,self)
    }
}
pub struct BStruct(i32);
impl<'a> Mapper<i32> for &'a mut BStruct{
    type Output=i32;
    fn map(self,value:i32)->(i32,Self){ 
        self.0=self.0+1;
        (value+self.0,self)
    }
}
/*
pub trait Mapper<Input>{
    type Output;
    fn map(mut self,value:Input)->Self::Output;
}
*/

just to avoid super odd (Self::Output,Self)
mb mut T is a type?

welp we need abstraction for this situation together with impl ... for &'a mut ...

let mut blaval=3;
fn foo(a:&mut i32){
    *a+=1;
}
let dwa=&mut blaval;
foo(dwa);//If we consider &mut i32 is a type, then ownership of dwa should be given
//&mut i32 is not Clone
foo(dwa);//logical, but what makes dwa to be still valid here
foo(dwa);

Sorry, what? Is there a question?

Your question is pretty unclear, but:

That's basically what a mutable reference &mut T does. While we don't often say that it "gives ownership" to the function, the function is free to move the T out of a &mut T as long as it immediately puts a (potentially different) T back in there, so "the ownership is returned" when the lifetime of the borrow expires.

3 Likes

This is unfortunately not true, this doesn't compile:

fn f(a: &mut String, b: String) {
    let c = *a;
    *a = b;
}
error[E0507]: cannot move out of `*a` which is behind a mutable reference

The reason has to do with panic unwinding.

No, that has nothing to do with panic unwinding. A simple assignment can't panic. This is purely because the compiler does not currently reason about places behind references like that. The functionally equivalent (and unsafely implemented)

let c = mem::replace(a, b);

works.

Unwinding would only matter if the replacement value weren't written to the place immediately, or at least before the first subsequent potentially panicking operation.

3 Likes

I changed my wording to say

- as long as it always puts a (potentially different) T back in there
+ as long as it immediately puts a (potentially different) T back in there

Yes, I meant mem::replace and its friends, as @paramagnetic pointed out.

let c = *a;
*a = b;

could compile if the borrow checker did an analysis of this kind. The reason it doesn't is probably that it would be impossible 99% of the time in the presence of unwinding (any function can panic, even deref coercion). And in the remaining 1%, you can use mem::replace anyway.

1 Like

Technically yes, but the indirect reason it is not implemented has to do with panic unwinding.

The compiler would have to check for possible panics, which would make the functionality very limited, and the type system currently doesn't have a way to mark which functions are non-panicking.

2 Likes

Are you guys sure that the caller of the function is willing to see ITS THIGNS get REPLACED by giving a &mut ?

Yes.

1 Like

That's the whole reason you give somebody a &mut T rather than a &T.

There is no difference between modifying something and replacing it. Replacing is one way to modify it, and vice-versa, you can think of all modifications as replacements of the old value with the new value.

1 Like