I'm writing atoi with state machine and it works perfectly.
struct Processor(Option<fn(processor: &mut Processor, c: char, a: &mut i32)>);
fn accu_add(c: char, a: &mut i32) {
*a = a.saturating_mul(10).saturating_add(c.to_digit(10).unwrap() as i32)
}
fn accu_sub(c: char, a: &mut i32) {
*a = a.saturating_mul(10).saturating_sub(c.to_digit(10).unwrap() as i32)
}
fn process_sign(processor: &mut Processor, c: char, a: &mut i32) {
match c {
c if c.is_whitespace() => (),
'+' => *processor = Processor(Some(process_positive_digit)),
'-' => *processor = Processor(Some(process_negative_digit)),
'0' ..= '9' => { *processor = Processor(Some(process_positive_digit)); accu_add(c, a) },
_ => *processor = Processor(None),
}
}
fn process_positive_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_add(c, a),
_ => *processor = Processor(None),
}
}
fn process_negative_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_sub(c, a),
_ => *processor = Processor(None),
}
}
impl Solution {
pub fn my_atoi(s: String) -> i32 {
let (mut processor, mut a) = (Processor(Some(process_sign)), 0);
for c in s.chars() {
match processor.0 {
Some(f) => f(&mut processor, c, &mut a),
None => return a,
}
}
return a;
}
}
But there are two functions which are too similar.
fn process_positive_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_add(c, a),
_ => *processor = Processor(None),
}
}
fn process_negative_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_sub(c, a),
_ => *processor = Processor(None),
}
}
So I want to generate the two functions with a super function (takes a function pointer and returns a function pointer), as bind does in js/ts.
Here is the code:
struct Processor(Option<fn(processor: &mut Processor, c: char, a: &mut i32)>);
fn accu_add(c: char, a: &mut i32) {
*a = a.saturating_mul(10).saturating_add(c.to_digit(10).unwrap() as i32)
}
fn accu_sub(c: char, a: &mut i32) {
*a = a.saturating_mul(10).saturating_sub(c.to_digit(10).unwrap() as i32)
}
fn process_sign(processor: &mut Processor, c: char, a: &mut i32) {
match c {
c if c.is_whitespace() => (),
'+' => *processor = Processor(Some(process_digit(accu_add))),
'-' => *processor = Processor(Some(process_negative_digit)),
'0' ..= '9' => { *processor = Processor(Some(process_positive_digit)); accu_add(c, a) },
_ => *processor = Processor(None),
}
}
fn process_digit(f: &'static fn(char, &mut i32)) -> impl Fn(&mut Processor, char, &mut i32) {
|processor: &mut Processor, c: char, a: &mut i32| match c {
'0' ..= '9' => f(c, a),
_ => *processor = Processor(None),
}
}
fn process_positive_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_add(c, a),
_ => *processor = Processor(None),
}
}
fn process_negative_digit(processor: &mut Processor, c: char, a: &mut i32) {
match c {
'0' ..= '9' => accu_sub(c, a),
_ => *processor = Processor(None),
}
}
impl Solution {
pub fn my_atoi(s: String) -> i32 {
let (mut processor, mut a) = (Processor(Some(process_sign)), 0);
for c in s.chars() {
match processor.0 {
Some(f) => f(&mut processor, c, &mut a),
None => return a,
}
}
return a;
}
}
Notice the super function here. I choose closure.
fn process_digit(f: &'static fn(char, &mut i32)) -> impl Fn(&mut Processor, char, &mut i32) {
|processor: &mut Processor, c: char, a: &mut i32| match c {
'0' ..= '9' => f(c, a),
_ => *processor = Processor(None),
}
}
Then the compiler refuses it defiantly.
Line 14: Char 58: error: mismatched types (solution.rs)
|
14 | '+' => *processor = Processor(Some(process_digit(accu_add))),
| ------------- ^^^^^^^^ expected `&fn(char, &mut i32)`, found fn item
| |
| arguments to this function are incorrect
|
= note: expected reference `&'static for<'a> fn(_, &'a mut _)`
found fn item `for<'a> fn(_, &'a mut _) {accu_add}`
Line 21: Char 4: note: function defined here (solution.rs)
|
21 | fn process_digit(f: &'static fn(char, &mut i32)) -> impl Fn(&mut Processor, char, &mut i32) {
| ^^^^^^^^^^^^^ ------------------------------
Line 14: Char 44: error: mismatched types (solution.rs)
|
14 | '+' => *processor = Processor(Some(process_digit(accu_add))),
| ---- ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found opaque type
| |
| arguments to this enum variant are incorrect
...
21 | fn process_digit(f: &'static fn(char, &mut i32)) -> impl Fn(&mut Processor, char, &mut i32) {
| --------------------------------------- the found opaque type
|
= note: expected fn pointer `for<'a, 'b> fn(&'a mut Processor, char, &'b mut i32)`
found opaque type `impl for<'a, 'b> Fn(&'a mut Processor, char, &'b mut i32)`
Line 14: Char 39: help: the type constructed contains `impl for<'a, 'b> Fn(&'a mut Processor, char, &'b mut i32)` due to the type of the argument passed (solution.rs)
|
14 | '+' => *processor = Processor(Some(process_digit(accu_add))),
| ^^^^^-----------------------^
| |
| this argument influences the type of `Some`
Line 596: Char 5: note: tuple variant defined here (solution.rs)
For more information about this error, try `rustc --explain E0308`.
error: could not compile `prog` (bin "prog") due to 2 previous errors
Question: Is it possible to generate a function pointer from another function pointer?