reference - referencia - pasar el valor de una variable de una clase a otra c#
¿Hay alguna forma de devolver una referencia a una variable creada en una función? (2)
¿Hay alguna manera de devolver una referencia de una función sin argumentos?
No (excepto las referencias a valores estáticos, pero aquí no son útiles).
Sin embargo, es posible que desee ver
OpenOptions::create
.
Si cambia su primera línea en
main
a
let f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
el archivo se creará si aún no existe, lo que debería resolver su problema original.
Quiero escribir un programa que escriba un archivo en 2 pasos. Es probable que el archivo no exista antes de ejecutar el programa. El nombre del archivo es fijo.
El problema es que
OpenOptions.new().write()
puede fallar.
En ese caso, quiero llamar a una función personalizada
trycreate()
.
La idea es crear el archivo en lugar de abrirlo y devolver un identificador.
Como el nombre de archivo es fijo,
trycreate()
no tiene argumentos y no puedo establecer una vida útil del valor devuelto.
¿Como puedo resolver este problema?
use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
fn trycreate() -> &OpenOptions {
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("ERR"),
};
f
}
fn main() {
{
let f = OpenOptions::new().write(true).open(b"foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => trycreate("foo.txt"),
};
let buf = b"test1/n";
let _ret = f.write(buf).unwrap();
}
println!("50%");
{
let f = OpenOptions::new().append(true).open("foo.txt");
let mut f = match f {
Ok(file) => file,
Err(_) => panic!("append"),
};
let buf = b"test2/n";
let _ret = f.write(buf).unwrap();
}
println!("Ok");
}
fjh es absolutamente correcto , pero quiero comentar un poco más profundamente y tocar algunos de los otros errores con su código.
Comencemos con un ejemplo más pequeño de devolver una referencia y observe los errores:
fn try_create<''a>() -> &''a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime ''a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<''a>() -> &''a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
¿Hay alguna manera de devolver una referencia de una función sin argumentos?
Técnicamente "sí", pero para lo que quieres, "no".
Una referencia apunta a una pieza de memoria existente.
En una función sin argumentos, las únicas cosas a las que se podría hacer referencia son las constantes globales (que tienen la vida útil
&''static
) y las variables locales.
Ignoraré los globales por ahora.
En un lenguaje como C o C ++, podría tomar una referencia a una variable local y devolverla. Sin embargo, tan pronto como la función regrese, no hay garantía de que la memoria a la que hace referencia continúe siendo lo que pensaba que era. Podría permanecer lo que espera por un tiempo, pero eventualmente la memoria se reutilizará para otra cosa. Tan pronto como su código mire la memoria e intente interpretar un nombre de usuario como la cantidad de dinero que queda en la cuenta bancaria del usuario, ¡surgirán problemas!
Esto es lo que previene la vida útil de Rust: no puede usar una referencia más allá de cuánto tiempo el valor al que se hace referencia es válido en su ubicación de memoria actual.
En lugar de intentar devolver una referencia, devuelva un objeto propio.
String
lugar de
&str
,
Vec<T>
lugar de
&[T]
,
T
lugar de
&T
, etc.
Ver también:
- ¿Es posible devolver un tipo prestado o propio en Rust?
- ¿Por qué puedo devolver una referencia a un literal local pero no a una variable?
Tu problema real
Mire la documentación de
OpenOptions::open
:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
Devuelve un
Result<File>
, por lo que no sé cómo esperaría devolver un
OpenOptions
o una referencia a uno.
Su función funcionaría si la reescribiera como:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn''t open")
}
Esto utiliza
Result::expect
entrar en pánico con un mensaje de error útil.
Por supuesto, entrar en pánico en las entrañas de su programa no es súper útil, por lo que se recomienda propagar sus errores:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option
y
Result
tienen muchos buenos métodos para lidiar con la lógica de error encadenado.
Aquí, puedes usar
or_else
:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
También devolvería el
Result
de
main
.
Todos juntos, incluidas las sugerencias de fjh:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1/n")?;
f.write_all(b"test2/n")?;
Ok(())
}