I have a function that takes 3 arguments namely a, b and a function that takes them and return the value that function produed.
fn from_func<T>(a: i32, b: i32, func: Fn) -> i32 {
func(a, b)
}
but when im calling it :
fn main() {
let my_func = |a: i32, b: i32| a + b;
println!("{:?}", from_func(15, 20, my_func));
}
I'm getting
error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
--> src\main.rs:5:34
|
5 | fn from_func<T>(a:i32,b:i32,func:Fn)->i32{
| ^^ help: specify the associated type: `Fn<Output = Type>`
I tried using where keyword and it worked
fn from_func<T>(a: i32, b: i32, func: T) -> i32
where
T: Fn(i32, i32) -> i32
{
func(a,b)
}
but is there any other way of doing this?
but is there any other way of doing this?
You must constrain the type variable to provide the arguments and return type of the function. You can do that with a where clause, which is probably best because it's on another line so makes the signature less cluttered.
But you could do this:
fn from_func<F: Fn(i32, i32) -> i32>(a: i32, b: i32, func: F) -> i32 {
func(a, b)
}
Or, avoid a named type variable by using an impl trait, like this:
fn from_func(a: i32, b: i32, func: impl Fn(i32, i32) -> i32) -> i32 {
func(a, b)
}
This question already has answers here:
Returning a closure from a method of a generic struct
(2 answers)
Closed 8 months ago.
I have a struct
struct A<F: Fn(i32)->i32>
How to define function which return it like
fn some_function() -> A<Fn(i32)->i32>
?
I think you need to use the fn type instead of the Fn trait:
struct A(fn(i32) -> i32);
fn some_function() -> A {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
You can of course also use the Fn trait, but then you need to use the impl keyword:
struct A<T: Fn(i32) -> i32>(T);
fn some_function() -> A<impl Fn(i32) -> i32> {
let square = |x| x * x;
A(square)
}
fn main() {
let f = some_function();
println!("{}", f.0(7));
}
49
impl here means "this is a type that I don't want to write here completely, but believe me, it implements Fn(i32) -> i32".
Is there a way to declare a generic trait that takes a function as the generic argument and uses it?
To clarify (Non-functioning code):
pub trait Test<F, T> where F: Fn(i32) -> T {
fn test(arg: i32) -> T {
let func: F;
func(arg)
}
}
You can associate specific functions when implementing a trait (didn't knew about this until now):
fn func() -> String {
String::from("hello")
}
trait MyTrait {
const FUNC: fn() -> String;
}
struct MyType;
impl MyTrait for MyType {
const FUNC: fn() -> String = func;
}
fn main() {
println!("{}", (MyType::FUNC)()); // prints hello
}
Playground
You can implement it somehow like this:
trait MyTrait<V: Sized + Fn() -> &'static str>: Sized {
fn construct(fun: V) -> Self;
fn get_fn(&self) -> &V;
fn call_inner(&self) {
println!("{}", (self.get_fn())());
}
}
struct FuncitonContainer<V>
where
V: Sized + Fn() -> &'static str,
{
f: V,
}
impl<V> MyTrait<V> for FuncitonContainer<V>
where
V: Sized + Fn() -> &'static str,
{
fn construct(fun: V) -> Self {
Self { f: fun }
}
fn get_fn(&self) -> &V {
&self.f
}
}
fn main() {
fn get_hello() -> &'static str {
"Hello"
}
FuncitonContainer::construct(get_hello).call_inner();
FuncitonContainer::construct(|| "World").call_inner();
}
It preserves function info and allows to use closures too. However, using it can be little more complex than Mihir's answer.
You can also look how Rust iterators are implemented: Rust iterators implementation
This question already has answers here:
How do you pass a Rust function as a parameter?
(2 answers)
Closed 4 years ago.
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(|x| x + 1, 5) // call
This function accepts both, closures and function pointers. It takes a function pointer as parameter type.
When should I prefer this over using a trait object, like &dyn Fn(i32) -> i32 or Box<dyn Fn(i32)-> i32> instead of fn
fn do_twice(f: &dyn Fn(i32) -> i32, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
do_twice(&|x| x + 1, 5) // call
or
fn do_twice(f: Box<dyn Fn(i32) -> i32>, arg: i32) -> i32 { // definition
f(arg) + f(arg)
}
When should I prefer this over using a trait object
Trait objects are not the only other option. As #DarthKotik pointed out, accepting a fn pointer will not permit closures that capture their environment, but you can just use a normal type parameter, bounded by Fn to accept both functions and closures, without needing to box anything:
fn do_twice<F>(f: F, arg: i32) -> i32
where
F: Fn(i32) -> i32
{
f(arg) + f(arg)
}
Or, equivalently, but avoiding an extra type variable:
fn do_twice(f: impl Fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn type is a bare function pointer (https://doc.rust-lang.org/std/primitive.fn.html).
It won't work with the closure that captures environment and it cannot be implemented manually for your fancy type (like impl Fn for MySuperType)
So the only reason why your examples working is the fact that it's oversimplified!
if you make it just a bit more complicated, it will fail https://gist.github.com/rust-play/2167e73325daa1e2a179505209405917
I need to deserialize a JSON into a struct that has a Vec<Vec<f64>> field. The JSON has strings for numbers so I need a custom deserializer to convert the strings to f64 during the deserialization.
A sample JSON that I'd like to deserialize:
{
"values": [["2", "1.4"], ["8.32", "1.5"]]
}
My struct is this:
#[derive(Deserialize)]
struct Payload {
#[serde(default, deserialize_with = "from_array_of_arrays_of_strs")]
values: Vec<Vec<f64>>,
}
I saw you could probably do this with visitors in the examples of Serde, so I've implemented this visitor:
fn from_array_of_arrays_of_strs<'de, T, D>(deserializer: D) -> Result<Vec<Vec<f64>>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
struct F64Visitor(PhantomData<fn() -> Vec<Vec<f64>>>);
impl<'de> Visitor<'de> for F64Visitor {
type Value = Vec<Vec<f64>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a nonempty sequence of numbers")
}
#[inline]
fn visit_str<E>(self, value: &str) -> Result<f64, E>
where
E: serde::de::Error,
{
self.visit_string(String::from(value))
}
#[inline]
fn visit_string<E>(self, value: String) -> Result<f64, E> {
Ok(value.parse::<f64>().unwrap())
}
#[inline]
fn visit_seq<V, T>(self, mut visitor: V) -> Result<Vec<T>, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(elem) = try!(visitor.next_element()) {
vec.push(elem);
}
Ok(vec)
}
}
let visitor = F64Visitor(PhantomData);
deserializer.deserialize_seq(visitor)
}
playground
The compiler complains that visit_str and visit_string have an incompatible type for the trait:
error[E0053]: method `visit_str` has an incompatible type for trait
--> src/main.rs:32:9
|
32 | / fn visit_str<E>(self, value: &str) -> Result<f64, E>
33 | | where
34 | | E: serde::de::Error,
35 | | {
36 | | self.visit_string(String::from(value))
37 | | }
| |_________^ expected struct `std::vec::Vec`, found f64
|
= note: expected type `fn(from_array_of_arrays_of_strs::F64Visitor, &str) -> std::result::Result<std::vec::Vec<std::vec::Vec<f64>>, E>`
found type `fn(from_array_of_arrays_of_strs::F64Visitor, &str) -> std::result::Result<f64, E>`
error[E0053]: method `visit_string` has an incompatible type for trait
--> src/main.rs:40:9
|
40 | / fn visit_string<E>(self, value: String) -> Result<f64, E> {
41 | | Ok(value.parse::<f64>().unwrap())
42 | | }
| |_________^ expected struct `std::vec::Vec`, found f64
|
= note: expected type `fn(from_array_of_arrays_of_strs::F64Visitor, std::string::String) -> std::result::Result<std::vec::Vec<std::vec::Vec<f64>>, E>`
found type `fn(from_array_of_arrays_of_strs::F64Visitor, std::string::String) -> std::result::Result<f64, E>`
error[E0049]: method `visit_seq` has 2 type parameters but its trait declaration has 1 type parameter
--> src/main.rs:45:21
|
45 | fn visit_seq<V, T>(self, mut visitor: V) -> Result<Vec<T>, V::Error>
| ^^^^^^ found 2 type parameters, expected 1
I think I don't have the correct understanding of how visitors work. Can I have only one visitor for deserializing the array of arrays of strings, or do I need one visitor for deserializing the arrays and one visitor for deserializing the strings to f64?
I've read:
How to transform fields before deserialization using serde?
Is there is a simpler way to convert a type upon deserialization?
As already described in How to transform fields before deserialization using serde?, the easiest solution is to introduce a newtype for your string-as-a-floating-point-value. You can then implement Deserialize for that, leveraging existing implementations of Deserialize and string parsing:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use serde::de::{Deserialize, Deserializer, Error, Unexpected};
#[derive(Debug, Deserialize)]
struct Payload {
#[serde(default)]
values: Vec<Vec<Value>>,
}
#[derive(Debug)]
struct Value(f64);
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where D: Deserializer<'de>
{
let s: &str = Deserialize::deserialize(deserializer)?;
s.parse()
.map(Value)
.map_err(|_| D::Error::invalid_value(Unexpected::Str(s), &"a floating point number as a string"))
}
}
fn main() {
let input = r#"
{
"values": [["2", "1.4"], ["8.32", "1.5"]]
}
"#;
let out: Payload = serde_json::from_str(input).unwrap();
println!("{:?}", out);
}
I prefer this solution because in many cases I want that new type to play a role in my system.
If you really, truly need to deserialize once and to exactly a Vec<Vec<f64>>, you have to implement two visitors. One will deserialize the outer Vec, one will deserialize the inner Vec. We will reuse the previous Value newtype, but the inner visitor will strip it away. The outer visitor will do the same thing for a newtype around the inner visitor:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Unexpected, Visitor};
use std::fmt;
#[derive(Debug, Deserialize)]
struct Payload {
#[serde(default, deserialize_with = "from_array_of_arrays_of_strs")]
values: Vec<Vec<f64>>,
}
fn from_array_of_arrays_of_strs<'de, D>(deserializer: D) -> Result<Vec<Vec<f64>>, D::Error>
where
D: Deserializer<'de>,
{
struct OuterVisitor;
impl<'de> Visitor<'de> for OuterVisitor {
type Value = Vec<Vec<f64>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a nonempty sequence of a sequence of numbers")
}
#[inline]
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(Inner(elem)) = try!(visitor.next_element()) {
vec.push(elem);
}
Ok(vec)
}
}
deserializer.deserialize_seq(OuterVisitor)
}
struct Inner(Vec<f64>);
impl<'de> Deserialize<'de> for Inner {
fn deserialize<D>(deserializer: D) -> Result<Inner, D::Error>
where
D: Deserializer<'de>,
{
struct InnerVisitor;
impl<'de> Visitor<'de> for InnerVisitor {
type Value = Inner;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a nonempty sequence of numbers")
}
#[inline]
fn visit_seq<V>(self, mut visitor: V) -> Result<Inner, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(Value(elem)) = try!(visitor.next_element()) {
vec.push(elem);
}
Ok(Inner(vec))
}
}
deserializer.deserialize_seq(InnerVisitor)
}
}
struct Value(f64);
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
s.parse().map(Value).map_err(|_| {
D::Error::invalid_value(Unexpected::Str(s), &"a floating point number as a string")
})
}
}
fn main() {
let input = r#"
{
"values": [["2", "1.4"], ["8.32", "1.5"]]
}
"#;
let out: Payload = serde_json::from_str(input).unwrap();
println!("{:?}", out);
}
Parsing JSON files with strings instead of numbers is also possible without writing a visitor yourself.
use serde_with::{serde_as, DisplayFromStr};
#[serde_as]
#[derive(Debug, serde::Deserialize)]
struct Payload {
#[serde_as(as = "Vec<Vec<DisplayFromStr>>")]
#[serde(default)]
values: Vec<Vec<f64>>,
}
let j = serde_json::json!({
"values": [["2", "1.4"], ["8.32", "1.5"]]
});
let p: Payload = serde_json::from_value(j)?;
assert_eq!(p.values, vec![vec![2.0, 1.4], vec![8.32, 1.5]]);
The annotation means that we have a Vec inside a Vec and the innermost elements should be deserialized using FromStr and serialized using Display. The annotation is supports any type with Display and FromStr implementations, so it can also be used on u64 or on Url types.