How to use a method as a function pointer in Rust - methods

I have a trait method that needs to mutate internal data of a struct and I was hoping I could pass a setter method as a parameter to the trait method. I want to do this so that I can be flexible with what gets mutated by specifying the function passed as a parameter.
This code is a simplification of what I am trying to do, it has the same compiler issue.
Thanks
Code
struct MyStruct {
i: usize
}
impl MyStruct {
fn set_i(mut self, i: usize) -> Self {
self.i = i;
self
}
fn new() -> Self{
MyStruct{ i: 0 }
}
}
trait MyTrait {
fn do_some_setting(&mut self, setter_function: fn(&mut Self, usize) -> Self ) {
setter_function(&mut self, 7);
}
}
impl MyTrait for MyStruct {}
fn main() {
let mut s = MyStruct::new()
.set_i(3);
assert_eq!(s.i, 3);
s.do_some_setting(MyStruct::set_i);
assert_eq!(s.i, 7);
}
Problem
error[E0308]: mismatched types
--> src/main.rs:27:23
|
27 | s.do_some_setting(MyStruct::set_i);
| ^^^^^^^^^^^^^^^ expected `&mut MyStruct`, found struct `MyStruct`
|
= note: expected fn pointer `for<'r> fn(&'r mut MyStruct, _) -> MyStruct`
found fn item `fn(MyStruct, _) -> MyStruct {MyStruct::set_i}`

This does not work because MyTrait::do_some_setting expects a function whose first parameter is of type &mut Self whereas the first parameter of MyStruct::set_i is of type mut self.
You can fix this by changing the signature of MyStruct::set_i to set_i(&mut self, i: usize) but then the compiler would complain about mismatched types as it expects MyStruct::set_i to return Self but you'd be returning &mut Self. You can either derive Clone and return the struct after cloning it, or you can change the return type in the signature to &mut Self.
The compiler will once again complain about mismatched types as setter_function in MyTrait::do_some_setting is a function that returns Self, not &mut Self. You'll have to change the signature of setter_function to return &mut Self.
The compiler will now complain that temporary value dropped while borrowed at let mut s = MyStruct::new().set_i(3). You'll have to create MyStruct first and then use set_i on it.
At last, you'll end up with code that looks as follows:
struct MyStruct {
i: usize,
}
impl MyStruct {
fn set_i(&mut self, i: usize) -> &mut Self {
self.i = i;
self
}
fn new() -> Self {
MyStruct { i: 0 }
}
}
trait MyTrait {
fn do_some_setting(&mut self, setter_function: fn(&mut Self, usize) -> &mut Self) {
setter_function(self, 7);
}
}
impl MyTrait for MyStruct {}
fn main() {
let mut s = MyStruct::new();
s.set_i(3);
assert_eq!(s.i, 3);
s.do_some_setting(MyStruct::set_i);
assert_eq!(s.i, 7);
}
Playground Link

Related

Function that returns a struct pointer as function that returns an interface

I have a package exporting a function that returns a struct pointer that I can't control. I'd like to wrap that function to provide a dependency seam so that I can do some unit testing. The idea is that I want a fake rather than what the external package is giving me.
An example looks like:
/////////////////////////////////////
// External Package I can't control.
/////////////////////////////////////
package ex
type Foo struct {
v int
}
func (f *Foo) GetV() int {
return f.v
}
func CreateFoo(v int) *Foo {
return &Foo{v: v}
}
////////////////////////////////////
// Local Package I'm testing.
////////////////////////////////////
type IFoo interface {
GetV() int
}
type factory = func(v int) IFoo
var factoryFn factory = ex.CreateFoo
This results in the error:
cannot use CreateFoo (type func(int) *Foo) as type func(int) IFoo in assignment
Since I think that *Foo is an IFoo, why not? What am I missing? Is there a way to achieve what I'm trying to do, giving myself a hook like that?
Playground link to example: https://play.golang.org/p/FDckAQGNRgA
The function type returning IFoo is a different type to the function returning *Foo even though Foo meets the requirements for IFoo, Go does not support covariance on the return type.
You would need to wrap the function
var factoryFn = func(v int) IFoo { return CreateFoo(v) }

Define string output for type in Golang

I'm wondering if there's a way through fmt to specify the way a string would get outputted for specific types. For example, I have a token struct that contains a bunch of information on the token, like token type (which is an int, but for clarity reasons, it would make more sense if I could output the name of the token type as a string).
So when I print a specific type of variable, is there a straightforward way to specify/implement the string output of such a type?
If that doesn't really make sense, Rust has an excellent form of doing so (from their doc)
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
let origin = Point { x: 0, y: 0 };
println!("The origin is: {}", origin); // prints "The origin is: (0, 0)"
You need to implement the interface Stringer, like this:
import "fmt"
type Point struct {
x int
y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func main() {
fmt.Println(Point{1, 2})
}
(Go Playground)
In Go you don't specify which interfaces a type implements, you just implements the required methods.

Generating Go method set with reflection

Is it possible to generate an interface or method set of a struct at runtime with reflection?
For example:
type S struct {
a int
}
func (s *S) Fn(b int) int {
return s.a + b
}
type I interface {
Fn(a int) int
}
func main() {
var x I = &S{a: 5}
fmt.Printf("%#v\n", x.Fn)
fmt.Printf("%#v\n", reflect.TypeOf(x).Method(0))
var y I
y.Fn = x.Fn // This fails, but I want to set y.Fn at runtime.
fmt.Printf("%#v\n", reflect.TypeOf(y).Method(0))
}
https://play.golang.org/p/agH2fQ4tZ_
To clarify, I'm trying to build a middleware library so interface I contains the http handlers and I want to wrap each hander with some sort of req/response logging so I need to return a new interface I where each function in new Interface I wraps the original + some logging.
Here's how to handle this for interfaces I and J.
type I interface { Fn1(a int) int }
type J interface { Fn2(a int) int }
type Y struct { // Y implements I by calling fn
fn func(a int) int
}
func (y Y) Fn1(a int) int { return y.fn(a) }
type Z struct { // Z implements J by calling fn
fn func(a int) int
}
func (z Z) Fn2(a int) int { return y.fn(a) }
var y I = Y{fn: x.Fn}
var z J = Z{fn: x.Fn}
There's no need to use reflection.
playground example

Prototyping struct in Go

My use case is, I need to have several structs in Go, who will have methods of same signatures and not necessarily have to have all the methods. The following code describes the requirements and also represents my current solution.
type calc struct {
fn func(a, b int) int
gn func(a string) bool
name string
}
func add(a, b int) int {
return a + b
}
func bar(foo string) bool {
// do something
}
func sub(a, b int) int {
return a - b
}
func main() {
for c := range []calc{{
fn: add,
gn: bar,
name: "addition",
}, {
fn: sub,
name: "subtraction",
}} {
fmt.Printf("%s(10, 15) returned: %d\n", c.name, c.fn(10, 15))
if c.gn != nil {
c.gn(c.name)
}
}
}
My question is how to improve this code? What's the best way to achieve this in Go? Can I achieve a better solution using interface?
Use interfaces.
type Op interface {
Name() string
Do(a, b int) int
}
type Add struct{}
func (Add) Name() string { return "add" }
func (Add) Do(a, b int) int { return a + b }
type Sub struct{}
func (Sub) Name() string { return "sub" }
func (Sub) Do(a, b int) int { return a - b }
Playground: http://play.golang.org/p/LjJt6D0hNF.
EDIT: Since you've edited your question, here is an example of how you could use asserting and interface to a broader interface for your task:
type RevOp interface {
Op
ReverseDo(a, b int) int
}
// ...
func (Add) ReverseDo(a, b int) int { return a - b }
// ...
fmt.Printf("%s(10, 15) returned: %d\n", op.Name(), op.Do(10, 15))
if op, ok := op.(RevOp); ok {
fmt.Printf("reverse of %s(10, 15) returned: %d\n", op.Name(), op.ReverseDo(10, 15))
}
Playground: http://play.golang.org/p/MQ6LlPDcEi.
I've discussed with some people in person and apparently my solution was correct. While it can be rewritten using interface, that's not necessarily an improvement.

Golang-like defer in Rust

In Go, you can use the defer keyword to execute a function when the current function returns, similar to the traditional finally keyword in other languages. This is useful for cleaning up state regardless of what happens throughout the function body. Here's an example from the Go blog:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
How can this functionality be achieved in Rust? I know about RAII, but in my specific case the state is in an external system. I'm writing a test that writes a key to a key-value store, and I need to make sure it's deleted at the end of the test regardless of whether or not the assertions in the test cause a panic.
I found this Gist but I don't know if this is a recommended approach. The unsafe destructor is worrisome.
There is also this issue on the Rust GitHub repository, but it's three years old and clearly not very relevant anymore.
(e: don't miss bluss's answer and their scopedguard crate, below.)
The correct way to achieve this by having code that runs in a destructor, like the defer! macro you link to does. For anything more than ad-hoc testing I would recommend writing a handle type with a proper destructor, e.g. one interacts with std::sync::Mutex via its MutexGuard type (returned by lock): there's no need to call unlock on the mutex itself. (The explicit handle-with-destructor approach is more flexible too: it has mutable access to the data, whereas the deferred approach may not be able to, due to Rust's strong aliasing controls.)
In any case, that macro is now (much!) improved due to recent changes, in particular, pnkfelix's sound generic drop work, which removes the necessity for #[unsafe_destructor]. The direct update would be:
struct ScopeCall<F: FnMut()> {
c: F
}
impl<F: FnMut()> Drop for ScopeCall<F> {
fn drop(&mut self) {
(self.c)();
}
}
macro_rules! defer {
($e:expr) => (
let _scope_call = ScopeCall { c: || -> () { $e; } };
)
}
fn main() {
let x = 42u8;
defer!(println!("defer 1"));
defer!({
println!("defer 2");
println!("inside defer {}", x)
});
println!("normal execution {}", x);
}
Output:
normal execution 42
defer 2
inside defer 42
defer 1
Although, it would be syntactically nicer as:
macro_rules! expr { ($e: expr) => { $e } } // tt hack
macro_rules! defer {
($($data: tt)*) => (
let _scope_call = ScopeCall {
c: || -> () { expr!({ $($data)* }) }
};
)
}
(The tt hack is necessary due to #5846.)
The use of the generic tt ("token tree") allows one to invoke it without the inner { ... } when there are multiple statements (i.e. it behaves more like a "normal" control flow structure):
defer! {
println!("defer 2");
println!("inside defer {}", x)
}
Also, for maximum flexibility about what the deferred code can do with captured variables, one could use FnOnce instead of FnMut:
struct ScopeCall<F: FnOnce()> {
c: Option<F>
}
impl<F: FnOnce()> Drop for ScopeCall<F> {
fn drop(&mut self) {
self.c.take().unwrap()()
}
}
That will also require constructing the ScopeCall with a Some around the value for c. The Option dance is required because calling a FnOnce moves ownership, which isn't possible from behind self: &mut ScopeCall<F> without it. (Doing this is OK, since the destructor only executes once.)
All in all:
struct ScopeCall<F: FnOnce()> {
c: Option<F>
}
impl<F: FnOnce()> Drop for ScopeCall<F> {
fn drop(&mut self) {
self.c.take().unwrap()()
}
}
macro_rules! expr { ($e: expr) => { $e } } // tt hack
macro_rules! defer {
($($data: tt)*) => (
let _scope_call = ScopeCall {
c: Some(|| -> () { expr!({ $($data)* }) })
};
)
}
fn main() {
let x = 42u8;
defer!(println!("defer 1"));
defer! {
println!("defer 2");
println!("inside defer {}", x)
}
println!("normal execution {}", x);
}
(Same output as the original.)
I use the following for a scope guard. It uses the Deref traits to provide shared & mutable access to the guarded value, without moving it out (that would invalidate the guard!)
My use case is correctly resetting the terminal when the program exits, even if panicking:
extern crate scopeguard;
use scopeguard::guard;
// ... terminal setup omitted ...
// Use a scope guard to restore terminal settings on quit/panic
let mut tty = guard(tty, |tty| {
// ... I use tty.write() here too ...
ts::tcsetattr(tty.as_raw_fd(), ts::TCSANOW, &old_attr).ok();
});
game_main(&mut tty).unwrap(); // Deref coercion magic hands off the inner &mut TTY pointer here.
Module scopeguard.rs:
use std::ops::{Deref, DerefMut};
pub struct Guard<T, F> where
F: FnMut(&mut T)
{
__dropfn: F,
__value: T,
}
pub fn guard<T, F>(v: T, dropfn: F) -> Guard<T, F> where
F: FnMut(&mut T)
{
Guard{__value: v, __dropfn: dropfn}
}
impl<T, F> Deref for Guard<T, F> where
F: FnMut(&mut T)
{
type Target = T;
fn deref(&self) -> &T
{
&self.__value
}
}
impl<T, F> DerefMut for Guard<T, F> where
F: FnMut(&mut T)
{
fn deref_mut(&mut self) -> &mut T
{
&mut self.__value
}
}
impl<T, F> Drop for Guard<T, F> where
F: FnMut(&mut T)
{
fn drop(&mut self) {
(self.__dropfn)(&mut self.__value)
}
}
This is now the crate scopeguard on crates.io.

Resources