|
Great :) > Does this make things like "const int * const x"
> (in C syntax) pointless in Rust?
Checking myself with cdecl, because I _always_ get this wrong: > declare x as const pointer to const int
This is let x: &i32;
(using i32 because it's the default int type, even though it's different than C's int.)The variations are: let x: &i32; // an immutable binding to an immutable reference
let mut x: &i32; // a mutable binding to an immutable reference
let x: &mut i32; // an immutable binding to a mutable reference
let mut x: &mut i32; // a mutable binding to a mutable reference
More mutablity == longer declaration, roughly. > Does that mean that in Rust I can only pass to a function an immutable reference
> to a mutable object,but not a mutable reference to an immutable object?
You're right in both. No problem treating something mutable as immutable, but treat something immutable as mutable and you get a compiler error. > Also, out of curiosity,
Rust has a concept called "slices". These are "fat pointers", that have both a pointer and a length inside: let x = vec![1, 2, 3, 4, 5];
let slice = &x[1..3];
Here, 'slice' will be a pair, (ptr, len), so the ptr will point to the interior of the vector, and the length will be 2. If we printed it, we'd see "2, 3".So let's check out the signature of recv: ssize_t recv(int sockfd, void *buf, size_t len, int flags);
This pointer, length pair looks suspiciously like buf and len here. That's for good reason. A first step towards a more Rust-like wrapper over recv would look like this: fn recv(socket: libc::c_int, buf: &mut [u8], flags: libc::c_int) -> libc::ssize_t {
let ptr = buf.as_mut_ptr() as *mut c_void;
let len = buf.len() as libc::size_t;
unsafe { recv(socket, ptr, len, flags) }
}
which would end up being called like this: recv(sock_fd, slice, 0);
combining the names from your example and mine from the slice above, heh.The next step would be to turn `flags` into an enum, and take that as an argument rather than a C int. Then you'd want to convert the return type to a Rust integer rather than a C one... eventually, you end up with the API we have in the standard library, which looks like this for a udp socket, for example: use std::net::UdpSocket;
{
let mut socket = try!(UdpSocket::bind("127.0.0.1:34254"));
// read ten bytes from the socket
let mut buf = [0; 10];
let (amt, src) = try!(socket.recv_from(&mut buf));
} // the socket is closed here
A few comments on this:We only said &mut buf, but I showed you syntax with [] above. When you pass a reference to an array or vector, and the function is expecting a slice, it will automatically convert to a slice of the full length. To be more accurate to your original question: let (amt, src) = try!(socket.recv_from(&mut buf[1, 5]));
or whatever middle part of the buffer you want.amt is the amount of bytes read, and the src is the address, in this particular API. You'll notice this particular API doesn't expose flags: we try to Do The Right Thing in the standard library, so you don't worry about these. Here's the source of rec_from: https://github.com/rust-lang/rust/blob/master/src/libstd/sys... c::recvfrom is libc::recvfrom, rather than recv, technically. But as an example from a different API, when opening files, we set O_CLOEXEC where appropriate: https://github.com/rust-lang/rust/pull/27971 If you want the more exotic options, then you have to dig in and make the calls yourself. Such is the pain of a standard library, trying to make the common, good case good, but we still let you dig in and build a different abstraction if you don't like ours. |