Skip to content

fn foo(&mut self) with a &mut [T] called with x.foo() copies the x slice instead of passing by reference #19147

Closed
@erickt

Description

@erickt

Here's an example:

use std::raw;
use std::mem;
use std::slice;
use std::io;
use std::io::{IoResult, IoError};

trait MyWriter {
    fn my_write(&mut self, buf: &[u8]) -> IoResult<()>;
}

impl<'a> MyWriter for &'a mut [u8] {
    fn my_write(&mut self, buf: &[u8]) -> IoResult<()> {
        let x: *mut &mut [u8] = self;
        println!("MyWriter ptr: {}", x);

        // return an error if the entire write does not fit in the buffer
        let write_len = buf.len();
        if write_len > self.len() {
            return Err(IoError {
                kind: io::OtherIoError,
                desc: "Trying to write past end of buffer",
                detail: None
            })
        }

        slice::bytes::copy_memory(*self, buf);

        println!("before: {}", self);

        unsafe {
            *self = mem::transmute(raw::Slice {
                data: self.as_ptr().offset(write_len as int),
                len: self.len() - write_len,
            });
        }

        println!("after:  {}", self);

        Ok(())
    }
}

fn main() {
    let mut buf = [0_u8, .. 6];
    println!("ptr: {}", buf);

    {
        let mut writer = buf.as_mut_slice();
        println!("writer: {}", writer);
        writer.my_write(&[0, 1, 2]).unwrap();
        println!("writer: {}", writer);
        writer.my_write(&[3, 4, 5]).unwrap();
        println!("writer: {}", writer);
    }
    println!("buf:    {}", buf);
    println!("");

    let mut buf = [0_u8, .. 6];
    println!("buf:    {}", buf);

    {
        let mut writer = buf.as_mut_slice();
        println!("writer: {}", writer);
        (&mut writer).my_write(&[0, 1, 2]).unwrap();
        println!("writer: {}", writer);
        (&mut writer).my_write(&[3, 4, 5]).unwrap();
        println!("writer: {}", writer);
    }
    println!("buf:    {}", buf);
    println!("");

    let mut buf = [0_u8, .. 6];
    println!("buf:    {}", buf);

    {
        let mut writer = buf.as_mut_slice();
        println!("writer: {}", writer);
        MyWriter::my_write(&mut writer, &[0, 1, 2]).unwrap();
        println!("writer: {}", writer);
        MyWriter::my_write(&mut writer, &[3, 4, 5]).unwrap();
        println!("writer: {}", writer);
    }
    println!("buf:    {}", buf);
    println!("");
}

This prints out the following output. You can see that using the writer.my_write(...) form passes in a different self address for each call, whereas explicitly using a &mut writer passes in the same address.

cc @nikomatsakis and @aturon. Niko on irc was suspecting this might be related to auto-ref-ref.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions