-1

I have a tokenizer superclass that can tokenize on an arbitrary string _string. I want to implement some "simple" tokenizers that can tokenize on common delimiters like space, newline, etc.

I have the following code:

api.rs

pub struct StringTokenizer { _string: &'static str }

The first subclass I'm trying to implement is a space tokenizer, so _string will be " ".

I tried to following:

simple.rs

use api::StringTokenizer;

impl StringTokenizer for SpaceTokenizer {
    let _string = " ";
}

and got the following error:

error: expected one of const, extern, fn, pub, type, unsafe, or }, found let

How can I give _string the value of " " in the subclass of StringTokenizer?

erip
  • 16,374
  • 11
  • 66
  • 121
  • Your terminology, code examples, and style are all very unusual for Rust. I'd **highly** recommend reading through the entire book, [*The Rust Programming Language*](http://doc.rust-lang.org/book/) and working through the exercises there. In doing so, you'd learn that there is no such thing as a "class" in Rust, much less a "subclass" or "superclass". Additionally, Rust structs do not use `_` to denote member variables (you may be thinking C++?). In fact, a prefix of `_`means "an unused variable". – Shepmaster Nov 22 '15 at 17:42
  • 3
    Sorry, not trying to be antagonistic! However, my point is that Rust *does not have classes*, so you cannot ask how to do something with a "Rust class" because the question is *mu*. There are questions that ask how to translate concepts from other languages into Rust; maybe that was your intention? Again, *in Rust*, `_` means an unused variable, no "potentially" about it. The compiler can do flow analysis to know if a variable may be used and will not complain about it if so. Feel free to ignore everything I say, but I'm also talking to future visitors that find this question. ^_^ – Shepmaster Nov 22 '15 at 17:54

1 Answers1

3

There are no "superclasses" and "subclasses" in Rust (as of 1.4.0). The best we have is traits.

For your case, I see two options. If the only difference between the tokenizer "classes" is the delimiter string, then I would have a single struct, and simply various constructor methods for each possible delimiter:

struct StringTokenizer {
    string: &'static str,
}

impl StringTokenizer {
    fn new_space() -> StringTokenizer {
        StringTokenizer { string: " " }
    }
}

If the classes need to be able to implement different behaviors, then you should use traits instead. You'd define a trait with a method that returns the delimiter string to use for each particular implementation. You could then add other methods as needed.

trait StringTokenizer {
    fn delimiter() -> &'static str;
}

struct SpaceTokenizer;

impl StringTokenizer for SpaceTokenizer {
    fn delimiter() -> &'static str {
        " "
    }
}

Note that the delimiter method here has no self, &self or &mut self parameter, which makes it a "static" method. For your other methods, you may need to add one of those as the first parameter.

To learn more about traits, read the section on Traits in The Rust Programming Language.

Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • This seems like it would result in a lot of rewritten code. What a pity. Thanks for the tips and the recommendations. – erip Nov 22 '15 at 17:36
  • 2
    @erip there are other ways of avoiding rewritten code, it's just that inheritance isn't the way. Composition works just fine for example, and often works better with Rust's emphasis on ownership. – Shepmaster Nov 22 '15 at 17:47
  • Rust doesn't offer class inheritance, so perhaps StringTokeniser should be a trait rather than a struct. (Traits roughly correspond to c# interfaces). Future versions of rust may allow you to define an associated_const when you implement a trait, but this is unstable and AFAICS it only works with integers https://doc.rust-lang.org/book/associated-constants.html Alternatively space_tokenizer could be a variable let space_tokenizer = StringTokenizer { string: " " } – nielsle Nov 22 '15 at 19:45
  • @nielsle `StringTokenizer` implements a trait `TokenizerI`. AFAIK Rust doesn't allow traits to implement traits. Temporarily I'll use the variable binding `space_tokenizer` until I decide to refactor. – erip Nov 23 '15 at 15:08
  • Here is some info on implementing a trait for all structs that implement another trait http://stackoverflow.com/questions/29256519/traits-implementing-traits Alternatively it might be cleaner to use a function `fn get_tokens( x: T) -> SomeIterator {..}` – nielsle Nov 25 '15 at 11:09