I'm about to return a string depending the given argument.
fn hello_world(name:Option<String>) -> String {
if Some(name) {
return String::formatted("Hello, World {}", name);
}
}
This is a not available associated function! - I wanted to make clear what I want to do. I browsed the doc already but couldn't find any string builder functions or something like that.
Use the format! macro:
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
In Rust, formatting strings uses the macro system because the format arguments are typechecked at compile time, which is implemented through a procedural macro.
There are other issues with your code:
You don't specify what to do for a None - you can't just "fail" to return a value.
The syntax for if is incorrect, you want if let to pattern match.
Stylistically, you want to use implicit returns when it's at the end of the block.
In many (but not all) cases, you want to accept a &str instead of a String.
See also:
Is there a way to pass named arguments to format macros without repeating the variable names?
Since Rust 1.58 it's possible to use named parameters, too.
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
Related
I'm about to return a string depending the given argument.
fn hello_world(name:Option<String>) -> String {
if Some(name) {
return String::formatted("Hello, World {}", name);
}
}
This is a not available associated function! - I wanted to make clear what I want to do. I browsed the doc already but couldn't find any string builder functions or something like that.
Use the format! macro:
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
In Rust, formatting strings uses the macro system because the format arguments are typechecked at compile time, which is implemented through a procedural macro.
There are other issues with your code:
You don't specify what to do for a None - you can't just "fail" to return a value.
The syntax for if is incorrect, you want if let to pattern match.
Stylistically, you want to use implicit returns when it's at the end of the block.
In many (but not all) cases, you want to accept a &str instead of a String.
See also:
Is there a way to pass named arguments to format macros without repeating the variable names?
Since Rust 1.58 it's possible to use named parameters, too.
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
I have a function like this
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
response = response.unwrap_or_else(|_e| {String::from("")});
response = response.text().unwrap_or_else(|_e| {String::from("")});
return response
}
Where I'm checking for html content. I would like to return an empty String if any kind of an error occurs somewhere in this function.
I'm not sure how to deal with this because unwrap_or_else expecting Result not String.
The reqwest::blocking::get() function is returning a Result<Response>.
To obtain the html, you have to unwrap this result and call .text() method.
That will return a Result<String>, that you have to unwrap again.
In your code you assign a String::from("") when you unwrap the Result<Response>, and that is not right, because you have a Response when it is Ok and a String when it is an Err.
Instead you should match the result and return the String from the function:
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
match response {
Ok(response) => response.text().unwrap_or_else(|_e| String::from("")),
Err(_) => String::from(""),
}
}
In this code, you use unwrap_or_else() just on the .text() result.
While if you have an error on the response itself, you return a String from the function.
An idiomatic way to solve your issue would be to refactor slightly your code: because code in get_html could fail, it's natural that its signature reflects this, so instead of returning a String, it could return an Option<String>, leaving the caller decide on what to do in this case:
fn get_html(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
See the playground.
This makes the code much more straightforward. However, you may really want the signature of the function to be -> String, not -> Option<String>. In this case, there are two solutions.
The first solution would be to use the experimental try block. I mention this solution, not because it's currently the most adequate, but because it will be one day (most likely).
fn get_html(address: &str) -> String {
let result: Option<_> = try {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()?
};
result.unwrap_or_default()
}
See the playground.
Note that, as is, Rust is not able to figure out types on its own for the try block, so we have to help it, which makes this more verbose. This aspect will probably improve over time, when try blocks are stabilized.
Also note that, since the Default::default constructor of String produces an empty string, we can directly use .unwrap_or_default() instead of .unwrap_or(String::new()) or .unwrap_or_else(|| String::new()) (since an empty string is not allocated, the first option is also acceptable).
The second solution would simply be to add an other function with the wanted signature, and make it use the first function
fn get_html_failable(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
fn get_html(address: &str) -> String {
get_html_failable(address).unwrap_or_default()
}
This may seem unconvenient, but lots of libraries in Rust have internal error propagation using types that represent failure (such as Result or Option), because it's really convenient to write such functions and to compose them (both reqwest::blocking::get and .text() return a Result, and see how easy it is to use them in a function that returns an Option), and have wrapper function that expose the wanted signature (most libraries will still expose fail types, but if you are writing an application it's not necessarily the best choice).
A variable of both preceding workarounds is to "simulate" a try block in stable Rust, without relying on an additional toplevel function.
fn get_html(address: &str) -> String {
(|| reqwest::blocking::get(address).ok()?.text().ok())()
.unwrap_or_default()
}
See the playground.
Note that, in this case, countrary to the try version, Rust is able to figure out the right types on its own.
This is probably the least readable solution, so I wouldn't recommend it (use try blocks instead). But it works.
So my question is whether this is possible, and if it is, how would one implement this.
For example,
fn some_fn(){}
let name = get_name_of(some_fn);
println!({}, name);
Which outputs
some_fn
Would an implementation like this be possible?
No, this currently does not seem to be possible as of 1.44.
Depending on your use case, you could of course still manually specify the name using macros such as println! or format the given function using stringify!.
For example, the following will print fn: some_fn:
fn main() {
println!("fn: {}", std::stringify!(some_fn));
}
fn some_fn() {}
The downside is that it simply prints the given argument and does not allow you to get the actual function name. Here's an example where it fails, as fn: f and not fn: some_fn will be returned:
fn main() {
some_fn_as_param(&some_fn);
}
fn some_fn() {}
fn some_fn_as_param(f: &dyn Fn()) {
println!("fn: {}", stringify!(f));
}
As mentioned in the comments, talk of such a macro for rust can be tracked here:
rust-lang/rfcs (issue), "Macro that expands into string holding function name (or module path, etc)"
rust-lang/rfcs (pr), "A macro to get the current function name."
I am implementing a function-like procedural macro which takes a single string literal as an argument, but I don't know how to get the value of the string literal.
If I print the variable, it shows a bunch of fields, which includes both the type and the value. They are clearly there, somewhere. How do I get them?
extern crate proc_macro;
use proc_macro::{TokenStream,TokenTree};
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input: Vec<TokenTree> = input.into_iter().collect();
let literal = match &input.get(0) {
Some(TokenTree::Literal(literal)) => literal,
_ => panic!()
};
// can't do anything with "literal"
// println!("{:?}", literal.lit.symbol); says "unknown field"
format!("{:?}", format!("{:?}", literal)).parse().unwrap()
}
#![feature(proc_macro_hygiene)]
extern crate macros;
fn main() {
let value = macros::my_macro!("hahaha");
println!("it is {}", value);
// prints "it is Literal { lit: Lit { kind: Str, symbol: "hahaha", suffix: None }, span: Span { lo: BytePos(100), hi: BytePos(108), ctxt: #0 } }"
}
After running into the same problem countless times already, I finally wrote a library to help with this: litrs on crates.io. It compiles faster than syn and lets you inspect your literals.
use std::convert::TryFrom;
use litrs::StringLit;
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input = input.into_iter().collect::<Vec<_>>();
if input.len() != 1 {
let msg = format!("expected exactly one input token, got {}", input.len());
return quote! { compile_error!(#msg) }.into();
}
let string_lit = match StringLit::try_from(&input[0]) {
// Error if the token is not a string literal
Err(e) => return e.to_compile_error(),
Ok(lit) => lit,
};
// `StringLit::value` returns the actual string value represented by the
// literal. Quotes are removed and escape sequences replaced with the
// corresponding value.
let v = string_lit.value();
// TODO: implement your logic here
}
See the documentation of litrs for more information.
To obtain more information about a literal, litrs uses the Display impl of Literal to obtain a string representation (as it would be written in source code) and then parses that string. For example, if the string starts with 0x one knows it has to be an integer literal, if it starts with r#" one knows it is a raw string literal. The crate syn does exactly the same.
Of course, it seems a bit wasteful to write and run a second parser given that rustc already parsed the literal. Yes, that's unfortunate and having a better API in proc_literal would be preferable. But right now, I think litrs (or syn if you are using syn anyway) are the best solutions.
(PS: I'm usually not a fan of promoting one's own libraries on Stack Overflow, but I am very familiar with the problem OP is having and I very much think litrs is the best tool for the job right now.)
If you're writing procedural macros, I'd recommend that you look into using the crates syn (for parsing) and quote (for code generation) instead of using proc-macro directly, since those are generally easier to deal with.
In this case, you can use syn::parse_macro_input to parse a token stream into any syntatic element of Rust (such as literals, expressions, functions), and will also take care of error messages in case parsing fails.
You can use LitStr to represent a string literal, if that's exactly what you need. The .value() function will give you a String with the contents of that literal.
You can use quote::quote to generate the output of the macro, and use # to insert the contents of a variable into the generated code.
use proc_macro::TokenStream;
use syn::{parse_macro_input, LitStr};
use quote::quote;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
// macro input must be `LitStr`, which is a string literal.
// if not, a relevant error message will be generated.
let input = parse_macro_input!(input as LitStr);
// get value of the string literal.
let str_value = input.value();
// do something with value...
let str_value = str_value.to_uppercase();
// generate code, include `str_value` variable (automatically encodes
// `String` as a string literal in the generated code)
(quote!{
#str_value
}).into()
}
I always want a string literal, so I found this solution that is good enough. Literal implements ToString, which I can then use with .parse().
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input: Vec<TokenTree> = input.into_iter().collect();
let value = match &input.get(0) {
Some(TokenTree::Literal(literal)) => literal.to_string(),
_ => panic!()
};
let str_value: String = value.parse().unwrap();
// do whatever
format!("{:?}", str_value).parse().unwrap()
}
I had similar problem for parsing doc attribute. It is also represented as a TokenStream. This is not exact answer but maybe will guide in a proper direction:
fn from(value: &Vec<Attribute>) -> Vec<String> {
let mut lines = Vec::new();
for attr in value {
if !attr.path.is_ident("doc") {
continue;
}
if let Ok(Meta::NameValue(nv)) = attr.parse_meta() {
if let Lit::Str(lit) = nv.lit {
lines.push(lit.value());
}
}
}
lines
}
I'm trying to make a Git command in Rust. I'm using the clap argument parser crate to do the command line handling. I want my command to take an optional argument for which directory to do work in. If the command does not receive the option it assumes the users home directory.
I know that I can use the std::env::home_dir function to get the user's home directory if it is set but the part that confuses me is how to properly use the match operator to get the value of the path. Here is what I've been trying:
use std::env;
fn main() {
// Do some argument parsing stuff...
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap()
} else {
match env::home_dir() {
Some(path) => path.to_str(),
None => panic!("Uh, oh!"),
}
};
// Do more things
I get an error message when I try to compile this saying that path.to_str() doesn't live long enough. I get that the value returned from to_str lives for the length of the match scope but how can you return a value from a match statement that has to call another function?
path.to_str() will return a &str reference to the inner string contained in path, which will only live as long as path, that is inside the match arm.
You can use to_owned to get an owned copy of that &str. You will have to adapt the value from clap accordingly to have the same types in both branches of your if:
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap().to_owned()
} else {
match env::home_dir() {
Some(path) => path.to_str().unwrap().to_owned(),
None => panic!("Uh, oh!"),
}
};
Alternatively, you could use Cow to avoid the copy in the first branch:
use std::borrow::Cow;
let some_dir: Cow<str> = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap().into()
} else {
match env::home_dir() {
Some(path) => path.to_str().unwrap().to_owned().into(),
None => panic!("Uh, oh!"),
}
};
What is happening is that the scope of the match statement takes ownership of the PathBuf object returned from env::home_dir(). You then attempt to return a reference to that object, but the object ceases to exist immediately.
The solution is to return PathBuf rather than a reference to it (or convert it to a String and return that instead, in any case, it has to be some type that owns the data). You may have to change what matches.value_of("some_dir").unwrap() returns so that both branches return the same type.
There is a rather simple trick: increase the scope of path (and thus its lifetime) so that you can take a reference into it.
use std::env;
fn main() {
// Do some argument parsing stuff...
let path; // <--
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap()
} else {
match env::home_dir() {
Some(p) => { path = p; path.to_str().unwrap() },
None => panic!("Uh, oh!"),
}
};
// Do more things
}
It is efficient, as path is only ever used when necessary, and does not require changing the types in the program.
Note: I added an .unwrap() after .to_str() because .to_str() returns an Option. And do note that the reason it returns an Option<&str> is because not all paths are valid UTF-8 sequences. You might want to stick to Path/PathBuf.