29

Here's my code:

let mut altbuf: Vec<u8> = Vec::new();

// Stuff here...

match stream.read_byte() {
    Ok(d) => altbuf.push(d),
    Err(e) => { println!("Error: {}", e); doneflag = true; }
}

for x in altbuf.iter() {
    println!("{}", x);
}

The code prints u8 bytes which are correct, but I can't figure out for the life of me how to convert a vector of pure u8 bytes into a string? The only other answer to a similar question on stack overflow assumes that you're working with a vector of type &[u8].

tshepang
  • 12,111
  • 21
  • 91
  • 136
AAnderson
  • 301
  • 1
  • 3
  • 4
  • Welcome to Stack Overflow! In the spirit of asking great questions, you may want to reword your question a bit. Your title makes it sound like you just want to [print the vector of bytes](http://is.gd/1kODTT), which is fairly easy. Your body makes it seem like you want to treat a sequence of bytes as a UTF-8 string, but you don't mention what encoding the bytes are in. You may also want to include some detail about what you are trying to do; perhaps a solution like [`read_to_string`](http://doc.rust-lang.org/std/io/trait.Reader.html#method.read_to_string) would solve your real problem. – Shepmaster Jan 24 '15 at 15:13

4 Answers4

24

If you look at the String documentation, there are a few methods you could use. There's String::from_utf8 that takes a Vec<u8>, and there's also String::from_utf8_lossy which takes a &[u8].

Note that a Vec<T> is more-or-less an owned, resizable wrapper around a [T]. That is, if you have a Vec<u8>, you can turn it into a &[u8], most easily by re-borrowing it (i.e. &*some_vec). You can also call any methods defined on &[T] directly on a Vec<T> (in general, this is true of things that implement the Deref trait).

DK.
  • 55,277
  • 5
  • 189
  • 162
  • Hi DK, could you please link me to a resource clarifying re-borrowing? To expand further, when I try to do println!("{}", &*altbuf); I get "trait core::fmt::String is not implemented for type [u8]". – AAnderson Jan 27 '15 at 03:23
  • 1
    @AAnderson: You probably want `println!("{:?}", &*altbuf)`. `{}` uses the `String` formatter which is for user-facing display, whilst `{:?}` is for just any sort of internal representation. Not everything *has* a `String` formatter, but almost everything has a `Show` formatter (which is what `{:?}` uses). To clarify re-borrowing: it's basically just calling `Deref::deref` on a thing and preserving the reference it returns (normally, the result of a `deref` call is automatically de-referenced; the extra `&` prevents that). I don't know of any more explicit explanation anywhere. – DK. Jan 27 '15 at 03:36
  • For printing, creating a `String` object is not necessary. `std::str::from_utf8` is enough. I left another answer including example code. – youknowone Apr 08 '22 at 00:40
5

If your altbuf is a vector of u8 as shown, this should work:

println!("{:?}", altbuf);

Here is an edited piece of code I have that does something similar:

let rebuilt: Vec<u8>;

unsafe {
    ret = proc_pidpath(pid, buffer_ptr, buffer_size);
    rebuilt = Vec::from_raw_parts(buffer_ptr as *mut u8, ret as usize, buffer_size as usize);
};

println!("Returned a {} byte string", ret);
println!("{:?}", rebuilt);

That rebuilds a vector of u8 values from a buffer filled by a C function called via FFI so the bytes could be anything, maybe not valid UTF-8.

When I run it, the output is:

Returned a 49 byte string

[47, 85, 115, 101, 114, 115, 47, 97, 110, 100, 114, 101, 119, 47, 46, 114, 98, 101, 110, 118, 47, 118, 101, 114, 115, 105, 111, 110, 115, 47, 49, 46, 57, 46, 51, 45, 112, 51, 57, 50, 47, 98, 105, 110, 47, 114, 117, 98, 121]

You could format the numbers printed (in hex, octal, etc) using different format strings inside the {}.

You can get a String from that using String::from_utf8(rebuilt) - which may return an error.

match String::from_utf8(rebuilt) {
    Ok(path) => Ok(path),
    Err(e) => Err(format!("Invalid UTF-8 sequence: {}", e)),
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Andrew Mackenzie
  • 5,477
  • 5
  • 48
  • 70
  • 1
    [Using a byte literal](http://play.integer32.com/?gist=f270884d23f154f96e98e2deaca6625b) would probably be a clearer example than using FFI and `unsafe`. Could you show an example of printing the entire slice as hex numbers? I [don't believe that works](http://stackoverflow.com/q/27650312/155423), but would be happy to be proven wrong. – Shepmaster Aug 16 '16 at 12:54
  • I think that's enough, and printing is different formats can be an exercise for the reader. – Andrew Mackenzie Aug 16 '16 at 12:56
3

To print bytes as a UTF-8 string, use std::str::from_utf8 when the bytes may be malformed. Use the unsafe std::str::from_utf8_unchecked when the bytes are always valid UTF-8.

println!("{}", std::str::from_utf8(&altbuf).unwrap());
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
youknowone
  • 919
  • 6
  • 14
3

Use the write method from std::io:

use std::{io, io::Write};

fn main() -> io::Result<()> {
   io::stdout().write(b"March\n")?;
   Ok(())
}

It prints a slice of u8, also known as a bytestring.

io::stdout

Zombo
  • 1
  • 62
  • 391
  • 407