That's just how Rust works.
More than that, that's how C works too:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char* name;
int32_t age;
} User;
void
UserInit(User* u){
printf("in init: user addr: %p
", u);
}
void
UserDoSomething(User* u){
printf("in do something user addr: %p
", u);
}
void
UserDestroy(User* u){
free(u->name);
}
User rust_like_new(void) {
User u;
UserInit(&u);
return u;
}
int main(int argc, char *argv[]) {
User u = rust_like_new();
UserDoSomething(&u);
}
in init: user addr: 0x7fff506c1600
in do something user addr: 0x7fff506c1630
Generally, you don't care about the address of the container, just what it contains.
If I heap allocate User
, the address won't change, but if I use Box
(let u = Box::new(User::new())
), it still changes.
The same thing happens in Rust and C. The address of the Box<User>
or User *
itself will change. The value (the pointed-at thing) of the Box<User>
or User *
will stay consistent.
mod ffi {
use std::mem;
use std::os::raw::c_char;
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: i32,
}
impl User {
pub fn new() -> Box<User> {
let mut ret: Box<User> = Box::new(unsafe { mem::uninitialized() });
unsafe { UserInit(&mut *ret) }
ret
}
pub fn do_something(&mut self) {
unsafe { UserDoSomething(self) }
}
}
extern "C" {
pub fn UserInit(u: *mut User);
pub fn UserDoSomething(u: *mut User);
}
}
use ffi::User;
fn main() {
let mut u = User::new();
u.do_something();
}
in init: user addr: 0x10da17000
in do something user addr: 0x10da17000
If you pass a reference to User
to C before it's moved into a Box
, then yes, the address will change when it's moved into the Box
. This would be the equivalent of:
User rust_like_new(void) {
User u;
UserInit(&u);
return u;
}
int main(int argc, char *argv[]) {
User u = rust_like_new();
User *u2 = malloc(sizeof(User));
*u2 = u;
UserDoSomething(u2);
}
Note that Rust (and other languages) allow for RVO to be performed. However, I believe that printing out the address would disqualify this optimization because the behavior would change if RVO was enabled. You'd need to look in a debugger or at the generated assembly.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…