Comments 18
А через as_bytes не получится нашаманить?
Про конкатенацию строк.
Я с растом мало имел дел, тонкостей могу не знать. Поискал, предлагают конкатенацию делать через интерполяцию с макро format!.. Это не то?
Я с растом мало имел дел, тонкостей могу не знать. Поискал, предлагают конкатенацию делать через интерполяцию с макро format!.. Это не то?
На самом деле преобразование String в &str делается очень просто. Во-первых, String реализует Deref<Target=str>, поэтому достаточно просто взять адрес от разыменованной строки или положиться на deref coercion, если целевой тип известен:
А поскольку String реализует Deref<Target=str>, а str реализует трейт Index<Range>, то можно воспользоваться slicing syntax:
Хотя использование deref coercion более идиоматично.
let s: String = "hello world".into();
let ss = &*s; // ss: &str
let ss: &str = &s; // deref coercion, потому что тип известен
А поскольку String реализует Deref<Target=str>, а str реализует трейт Index<Range>, то можно воспользоваться slicing syntax:
let ss = &s[..];
Хотя использование deref coercion более идиоматично.
Очень плохо, что в документации as_str() не написано, почему он unstable. Он таков, потому что, вполне вероятно, он будет задепрекейчен. Вероятно, имеет смысл создать ишью в трекере Rust на эту тему.
И ещё, to_string() не рекомендуется использовать для преобразования &str в String потому что он несёт накладные расходы — он использует механизм std::fmt вместо того, чтобы напрямую создать новую строку и скопировать байты. Поэтому лучше использовать to_owned() (если целевой тип неизвестен) или into() (если известен).
И последнее — поиск в гугле по запросу «rust string to str» в первых ссылках даёт вот этот вопрос и ответ на stackoverflow, где объясняются все вышеописанные варианты (хоть и название вопроса немного не то).
Для чего вам вообще склеивать str? Он для этого не предназначен. Его можно сравнить с Сишным
String предназначен для манипуляции строками. Более того, вам даже он не нужен.
Вы хотите передавать путь до файла в функцию — так и принимайте его! Для манипуляции Path есть тонна удобнейших функций.
gist mirror
char *
— просто немодифицируемая последовательность символов.String предназначен для манипуляции строками. Более того, вам даже он не нужен.
Вы хотите передавать путь до файла в функцию — так и принимайте его! Для манипуляции Path есть тонна удобнейших функций.
std::path::Path usage
use std::path::Path;
struct Model {
u: f32,
}
impl Model {
fn new(file_path: &Path) -> Model {
let texture_path = file_path.with_extension("tga");
println!("path: {:?}", texture_path);
// outputs 'path: "/tmp/models/african_head.tga"'
Model{ u: 1.0 }
}
}
fn main() {
let model = Model::new(Path::new("/tmp/models/african_head.obj"));
}
gist mirror
Мне не просто расширение поменять надо. Еще к имени файла прибавить суффикс "_diffuse". Когда писал это дело, я искал, как прибавить суффикс к имени файла средствами std::path::Path. Не нашел. Может плохо искал?
А, теперь я понял, для чего вам конкатенация.
Тогда вот вариант с использованием
Вот здесь ещё несколько вариантов: stackoverflow.com/a/30481077/1145239
Я бы на вашем месте просто сменил расширение или складывал в другую директорию.
Тогда вот вариант с использованием
format!
и PathBuf
(на gist тоже обновил, ссылка выше):Скрытый текст
use std::path::{Path, PathBuf};
struct Model {
u: f32,
}
fn texture_fname(path: &Path) -> PathBuf {
let fullname = format!("{}{}", path.file_stem().unwrap().to_str().unwrap(), "_diffuse");
let mut buf = PathBuf::from(path);
buf.set_file_name(fullname);
buf.set_extension("tga");
buf
}
impl Model {
fn new(texture_path: &Path) -> Model {
let texture_path = texture_fname(texture_path);
println!("path: {:?}", texture_path.as_path());
// outputs 'path: "/tmp/models/african_head_diffuse.tga"'
Model{ u: 1.0 }
}
}
fn main() {
let model = Model::new(Path::new("/tmp/models/african_head.obj"));
}
Вот здесь ещё несколько вариантов: stackoverflow.com/a/30481077/1145239
Я бы на вашем месте просто сменил расширение или складывал в другую директорию.
Вот вариант без функции, наиболее близок к вашему коду:
На мой взгляд, здесь несколько недостатков:
Скрытый текст
use std::path::{Path, PathBuf};
struct Model {
u: f32,
}
impl Model {
fn new(texture_path: &str) -> Model {
let buf = PathBuf::from(texture_path);
let texture_path = format!("{}/{}{}",
buf.parent().unwrap().to_str().unwrap(),
buf.file_stem().unwrap().to_str().unwrap(),
"_diffuse.tga");
println!("path: {:?}", texture_path);
// outputs 'path: "/tmp/models/african_head_diffuse.tga"'
Model{ u: 1.0 }
}
}
fn main() {
let model = Model::new("/tmp/models/african_head.obj");
}
На мой взгляд, здесь несколько недостатков:
- Используются непортируемые разделители директорий /
- Менее очевидно, что в
Model::new
передаётся именно путь до файла - Меньшая гибкость — когда генерация имени вынесена в отдельную функцию, её легче повторно использовать и менять.
А почему
format!("{}{}", path.file_stem().unwrap().to_str().unwrap(), "_diffuse");
а не format!("{}_diffuse", path.file_stem().unwrap().to_str().unwrap());
Sign up to leave a comment.
Пишем свой упрощенный OpenGL на Rust — часть 3 (растеризатор)