Given the following struct (in practice, its bigger than this):
#[derive(Deserialize, Debug)]
struct Parameter {
name: String,
value: String,
}
If I want to create an instance of this (for tests, etc.):
Parameter {
name: "name".to_string(),
value: "value".to_string()
}
I have to call to_string on the end of all my values. This is a bit annoying. Is there a shorthand way of creating an owned string?
You could always shorten it with a macro:
macro_rules! s {
($s:expr) => { $s.to_string() }
}
#[derive(Debug)]
struct Parameter {
name: String,
value: String,
}
fn main() {
println!("{:?}", Parameter { name: s!("foo"), value: s!("bar"), });
}
Playground
The macro by Jmb works fine, but I prefer to use plain functions where possible. (I also prefer post-fix operations over prefix+postfix ones)
So this is the variant I have used:
pub trait ToStringExt : ToString {
/// Simply an alias for `.to_string()`.
fn s(&self) -> String {
self.to_string()
}
}
impl<T> ToStringExt for T where T: ToString {}
And then to use it:
use to_string_ext::ToStringExt;
fn main() {
let my_str: String = "some string".s();
}
If the only case where you want this shorthand is converting a &str into a String, then this is a narrower alternative: (which I prefer nowadays)
pub trait ToOwnedExt where Self : ToOwned {
/// Simply an alias for `.to_owned()`.
fn o(&self) -> <Self as ToOwned>::Owned {
self.to_owned()
}
}
impl<T: ?Sized> ToOwnedExt for T where T: ToOwned {}
And then to use it:
use to_owned_ext::ToOwnedExt;
fn main() {
let my_str: String = "some string".o();
}
Related
Is there a better way to access the contents of an Enum that in the various cases shares the same variable type?
At the moment I have solved it this way:
enum Token<'a> {
Word(&'a str),
Reserved(&'a str),
Whitespace(&'a str),
}
impl<'a> ToString for Token<'a> {
fn to_string(&self) -> String {
match self {
Self::Word(str) | Self::Reserved(str) | Self::Whitespace(str) => str.to_string(),
}
}
}
Not with this implementation. But you could (and maybe should) instead have
enum TokenKind {
Word,
Reserved,
Whitespace,
}
struct Token<'a> {
string: &'a str,
kind: TokenKind
}
This is more extensible, and less code duplication.
A typical AST implementation in C might look like:
typedef enum {
AST_IDENT,
AST_STRING,
} Ast_Tag;
typedef struct { Ast_Tag tag; u32 flags; } Ast;
typedef struct { Ast base; Intern *name; } Ast_Ident;
typedef struct { Ast base; Intern *str; } Ast_String;
// A function that downcasts to the derived type:
void foo (Ast *node) {
switch (node->tag) {
case AST_IDENT: {
Ast_Ident *ident = (Ast_Ident*)node;
do_something_with_name(ident->name);
} break;
case AST_STRING: {
Ast_String *str = (Ast_String*)node;
do_something_with_name(str->name);
} break;
}
}
// A function that upcasts to the base type:
void bar (Ast_Ident *ident) {
foo((Ast*)ident);
}
Is there a way to do this in rust? I'd imagine that downcasting would be particularly problematic.
NOTE: I'm not asking how to implement an AST, but how to replicate the struct inheritance as demonstrated above.
EDIT: Sorry for the confusion. The point here is that struct inheritance is used in order to avoid making every node be the same size, so enums are not an option.
You basically implement Rust enum variant:
struct Ast {
flags: u32,
kind: AstKind,
}
enum AstKind {
Ident(String),
String(String),
}
fn foo(ast: Ast) {
match ast.kind {
AstKind::Ident(ident) => println!("flags: {:?}, ident: {:?}", ast.flags, ident),
AstKind::String(s) => println!("string: {:?}, ident: {:?}", ast.flags, s),
}
}
fn bar(flags: u32, ident: String) {
foo(Ast {
flags,
kind: AstKind::Ident(ident),
})
}
fn main() {
bar(42, "MisterMV".into())
}
You seem to be concern with the size:
The point here is that struct inheritance is used in order to avoid making every node be the same size, so enums are not an option.
That generally not a concern, clippy have a lint call large_enum_variant, with a reasonable default that you can change. Clippy also propose a reasonable solution:
enum AstKind {
Ident(Box<Big>),
String(Small),
}
There are other alternatives that other answer already cover.
You can reference multiple types as a trait, but you can't cast the trait object to the exact type. To the rescue is the Any trait, which has a is, downcast_ref, and Box<dyn Any> has a downcast method. You can also get type IDs.
But there is no inheritance like you see in many OOP languages. That goal is accomplished by implementing traits.
That's impossible in safe Rust. You can however do it with transmute, provided that your structs are all repr(C):
pub enum AstTag {
AstIdent,
AstString,
}
#[repr(C)]
pub struct Ast { tag: AstTag, flags: u32, }
#[repr(C)]
pub struct AstIdent { base: Ast, name: String, }
#[repr(C)]
pub struct AstString { base: Ast, string: String, }
// A function that downcasts to the derived type:
pub fn foo (node: &Ast) {
use std::mem::transmute;
match node.tag {
AstTag::AstIdent => {
let ident: &AstIdent = unsafe { transmute (node) };
println!("{}", ident.name);
},
AstTag::AstString => {
let ident: &AstString = unsafe { transmute (node) };
println!("{}", ident.string);
}
}
}
// A function that upcasts to the base type:
pub fn bar (ident: &AstIdent) {
foo (&ident.base);
}
Playground
However this is very unidiomatic. A much more idiomatic way of doing things would be to put foo in a trait and implement that trait for each struct:
pub struct AstIdent { flags: u32, name: String, }
pub struct AstString { flags: u32, string: String, }
pub trait Foo {
fn foo (&self);
}
impl Foo for AstIdent {
fn foo (&self) {
println!("{}", self.name);
}
}
impl Foo for AstString {
fn foo (&self) {
println!("{}", self.string);
}
}
pub fn bar (ident: &AstIdent) {
ident.foo();
}
Playground
I am currently implementing decorator pattern in Rust.
In Scala we could implement method chaining via traits like:
new Scanner
with Whitespaces
with Keywords
I want to do the same in Rust. So, different traits for scanner:
pub struct Lexer();
pub trait Scan {
fn scan(&self, start: &String) -> DomainTags;
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Scan> Scan for Keywords<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Scan> Scan for Whitespaces<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
But since I want to build my lexers with method like:
pub fn build() -> ??? {
let lex = Lexer();
let lex = Keyword {
decorated: Whitespaces {
decorated: lex
}
};
lex
}
I don't know if it is possible to statically deduce the return type to something like decltype(lex). What is the common approach, towards implementing the method? What could be improved?
To clarify: I want to return decltype(lex), because I may also have multiple traits for single Lexer, like:
pub trait Load {
fn load<T : Load>(&self, keywords: &String);
}
impl Load for Lexer {
fn load<Lexer>(&self, keyword : &String) {
...
}
}
And I hope to return a decorated object with implementation of Load trait as well. Both method load and scan should be available.
A function can only return a single type of value, so the type returned by your function can't depend on runtime conditions. However that type may be a boxed trait, in which case the type of the value stored in the box may change provided it implements the appropriate trait (or traits).
From the example code you've provided, I think that Lexer should be a trait like trait Lexer: Scan + Load {} (or maybe the Scan and Load traits don't need to exist at all and the scan and load methods can be defined directly in Lexer). Then your build function should just return a boxed Lexer:
pub trait Lexer {
fn scan (&self, start: &String) -> DomainTags;
fn load (&self, keyword : &String);
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Lexer> Lexer for Keywords<T> {
…
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Lexer> Lexer for Whitespaces<T> {
…
}
pub fn build (cond: bool) -> Box<dyn Lexer> {
if cond {
Box::new (Whitespaces { … })
} else {
Box::new (Keywords { … })
}
}
I have the following:
pub struct OpBStruct {
title: String,
output_vale: i32,
}
impl OpBStruct {
pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
OpBStruct {
title: in_title,
output_vale: in_output_vale,
}
}
}
pub struct OpCStruct {
title: String,
another_value: String,
output_vale: i32,
}
impl OpCStruct {
pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
OpCStruct {
title: in_title,
another_value: in_another_value,
output_vale: in_output_vale,
}
}
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
pub enum Op {
OpB(OpBStruct),
OpC(OpCStruct),
}
pub struct A {
name: String,
operator: Op,
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
The exact structure of OpBStruct and OpCStruct are arbitrary and could be anything.
How do I make sure OpBStruct and OpCStruct implement a certain trait?
trait OpTrait {
pub fn get_op_output(&self) -> i32;
}
I thought about making a sort of constructor function that checked for an OpTrait trait requirement and it would be the only way one could create an Op instance, but each operator requires different initialization parameters and there's no way to specify a variable number of inputs for a function in Rust.
Something like this doesn't work because there's no way to input the initialization parameters:
pub fn new_op<T: OpTrait>(operator: T) {
// --snip--
}
I thought about somehow using the new_A method implemented on A to check if the in_operator has implemented the trait, but I'm not sure how to do that either.
What is the correct pattern for this? If there is none, I can just implement the trait for each Op with no sort of interface around it.
I would also recommend writing a test, however you can write a function which is generic over a type but takes no arguments:
struct X {}
trait Y {
fn yo();
}
fn is_y<T: Y>(){}
Then you can add the following line to do the check
is_y::<X>();
which will compile only if X implements Y.
Using a unit test would be a fairly straightforward way to enforce that you want a given trait on a struct. You can do it via implicit test code, but a small utility function to do so can express the intent a little more clearly.
If you have indicated trait inputs on functions in the rest of the code, it might come out fairly naturally without the unit test. The test has the advantage of letting you have an opportunity to explicitly check some invariant of the trait implementation too.
struct A {
val: u8,
}
struct B {
val: u32,
}
trait ExpandToU64 {
fn to_u64(&self) -> u64;
}
impl ExpandToU64 for A {
fn to_u64(&self) -> u64
{
self.val as u64
}
}
fn trait_tester<E>(a: E)
where E: ExpandToU64
{
// the utility function doesn't have to even use the trait...
// but you probably want to exercise the logic a bit
//let v = a.to_u64();
let v = 24u64;
println!("{:?}", v);
}
#[test]
fn test_needs_trait_ExpandToU64() {
let a = A { val:1 };
trait_tester(a);
let b = B { val:2 };
trait_tester(b);
// This fails with a compile error
// "the trait `ExpandToU64` is not implemented for `B`"
}
I'm trying to do the equivalent of Ruby's Enumerable.collect() in Rust.
I have an Option<Vec<Attachment>> and I want to create a Option<Vec<String>> from it, with String::new() elements in case of None guid.
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<String>> = match ov {
Some(x) => {
x.iter()
.map(|&attachment| attachment.guid.unwrap_or(String::new()))
.collect()
}
None => None,
};
}
The error in the compiler is clear:
error[E0277]: the trait bound `std::option::Option<std::vec::Vec<std::string::String>>: std::iter::FromIterator<std::string::String>` is not satisfied
--> src/main.rs:15:18
|
15 | .collect()
| ^^^^^^^ the trait `std::iter::FromIterator<std::string::String>` is not implemented for `std::option::Option<std::vec::Vec<std::string::String>>`
|
= note: a collection of type `std::option::Option<std::vec::Vec<std::string::String>>` cannot be built from an iterator over elements of type `std::string::String`
If I remember what I've read from the documentation so far, I cannot implement traits for struct that I don't own.
How can I do this using iter().map(...).collect() or maybe another way?
You should read and memorize all of the methods on Option (and Result). These are used so pervasively in Rust that knowing what is present will help you immensely.
For example, your match statement is Option::map.
Since you never said you couldn't transfer ownership of the Strings, I'd just do that. This will avoid any extra allocation:
let foo: Option<Vec<_>> =
ov.map(|i| i.into_iter().map(|a| a.guid.unwrap_or_else(String::new)).collect());
Note we don't have to specify the type inside the Vec; it can be inferred.
You can of course introduce functions to make it cleaner:
impl Attachment {
fn into_guid(self) -> String {
self.guid.unwrap_or_else(String::new)
}
}
// ...
let foo: Option<Vec<_>> = ov.map(|i| i.into_iter().map(Attachment::into_guid).collect());
If you don't want to give up ownership of the String, you can do the same concept but with a string slice:
impl Attachment {
fn guid(&self) -> &str {
self.guid.as_ref().map_or("", String::as_str)
}
}
// ...
let foo: Option<Vec<_>> = ov.as_ref().map(|i| i.iter().map(|a| a.guid().to_owned()).collect());
Here, we have to use Option::as_ref to avoid moving the guid out of the Attachment, then convert to a &str with String::as_str, providing a default value. We likewise don't take ownership of the Option of ov, and thus need to iterate over references, and ultimately allocate new Strings with ToOwned.
Here is a solution that works:
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<_>> = ov.map(|x|
x.iter().map(|a| a.guid.as_ref().unwrap_or(&String::new()).clone()).collect());
println!("{:?}", foo);
}
One of the issues with the above code is stopping the guid being moved out of the Attachment and into the vector. My example calls clone to move cloned instances into the vector.
This works, but I think it looks nicer wrapped in a trait impl for Option<T>. Perhaps this is a better ... option ...:
trait CloneOr<T, U>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T;
}
impl<T, U> CloneOr<T, U> for Option<T>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T {
self.as_ref().unwrap_or(&other.into()).clone()
}
}
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) },
Attachment { guid: None }]);
let foo: Option<Vec<_>> =
ov.map(|x| x.iter().map(|a| a.guid.clone_or("")).collect());
println!("{:?}", foo);
}
Essentially the unwrapping and cloning is hidden behind a trait implementation that attaches to Option<T>.
Here it is running on the playground.