I've been playing around with Rust the past week. I can't seem to figure out how to pass a function that is defined as a parameter when calling the method, and haven't come across any documentation that shows them being used in that fashion.
Is it possible to define a function in the parameter list when calling a function in Rust?
This is what I've tried so far...
fn main() {
// This works
thing_to_do(able_to_pass);
// Does not work
thing_to_do(fn() {
println!("found fn in indent position");
});
// Not the same type
thing_to_do(|| {
println!("mismatched types: expected `fn()` but found `||`")
});
}
fn thing_to_do(execute: fn()) {
execute();
}
fn able_to_pass() {
println!("Hey, I worked!");
}
In Rust 1.0, the syntax for closure parameters is as follows:
fn main() {
thing_to_do(able_to_pass);
thing_to_do(|| {
println!("works!");
});
}
fn thing_to_do<F: FnOnce()>(func: F) {
func();
}
fn able_to_pass() {
println!("works!");
}
We define a generic type constrained to one of the closure traits: FnOnce, FnMut, or Fn.
Like elsewhere in Rust, you can use a where clause instead:
fn thing_to_do<F>(func: F)
where F: FnOnce(),
{
func();
}
You may also want to take a trait object instead:
fn main() {
thing_to_do(&able_to_pass);
thing_to_do(&|| {
println!("works!");
});
}
fn thing_to_do(func: &Fn()) {
func();
}
fn able_to_pass() {
println!("works!");
}
Related
Similar, I believe, to an applicative, I would like to wrap a higher-order function in some context and apply it to a sequence.
protocol Foo { func a() -> Void }
class Bar: Foo { func a() { } }
let seq = [Bar(), Bar(), Bar()]
Concretely, Give the above three definitions, I'd like to be able to call dispatch(event) where dispatch wraps up a forEach over a sequence of protocol instances, and event is a function defined by that protocol.
private func dispatch(event: () -> Void) -> Void {
DispatchQueue.main.async { // context that the forEach mapping should happen inside of
seq.forEach($0.event())
}
}
let _ = dispatch(Foo.a)
Obviously, this doesn't work with Swift's type system (I'm used to Clojure's apply()). As a possible alternative, is there a way to wrap the sequence into a partial that I can forEach on?
let dispatch() -> [Foo] {
DispatchQueue.main.async {
seq.forEach // 🤷🏻♂️
}
}
let _ = dispatch { $0.a() }
Perhaps dispatch should be thought of as a constrained extension to Sequence?
extension Sequence where Iterator.Element == Foo {
func dispatch() -> [Foo] {
DispatchQueue.main.async {
return self.forEach // 🤷🏾♀️
}
}
}
While not as elegant as could have been with key paths to instance methods, you could also create a dispatch function that takes in a closure with each element as its parameter:
func dispatch(_ handler: #escaping (Foo) -> Void) {
DispatchQueue.main.async {
seq.forEach(handler)
}
}
And invoke it like so:
dispatch { $0.a() }
While you can't use KeyPath for instance methods, you can use it for properties, if it works for you.
You can change your protocol and implementation to something like this:
protocol Foo {
var a: () -> Void { get }
}
class Bar: Foo {
lazy var a = {
print("Bar")
}
}
Then you can define your dispatch function to take a KeyPath as parameter:
extension Sequence where Iterator.Element: Foo {
func dispatch(keyPath: KeyPath<Foo, () -> Void>) {
DispatchQueue.main.async {
forEach { $0[keyPath: keyPath]() }
}
}
}
and pass the properties KeyPath as parameter:
let seq = [Bar(), Bar(), Bar()]
seq.dispatch(keyPath: \Foo.a)
I created macro for printing, using proc-macro-hack.
Then this error occured though I already have defined a.
Following is the code.
On decl crate,
proc_macro_expr_decl! {
/// Function for printing to the standard output.
///
/// First argument can be literal or not literal.
gprint! => gprint_impl
}
On impl crate,
use syn::{Expr, ExprTuple, parse_str};
use quote::ToTokens;
fn _print_impl(input: &str, print_name: &str) -> String {
let mut input_with_parens = String::with_capacity(input.len() + 2);
input_with_parens.push('(');
input_with_parens.push_str(input);
input_with_parens.push(')');
let tuple = parse_str::<ExprTuple>(&input_with_parens)
.unwrap_or_else(|_| panic!("expected arguments is expressions separated by comma, found {}", input))
let mut arg_iter = tuple.elems.iter();
let first = arg_iter.next();
if first.is_none() {
return "()".to_string();
}
let first = first.unwrap();
let mut s = String::new();
if let &Expr::Lit(ref lit) = first {
s.push_str(print_name);
s.push('(');
s.push_str(&lit.into_tokens().to_string());
} else {
s.push_str(print_name);
s.push_str("(\"{}\", ");
s.push_str(&first.into_tokens().to_string());
}
for arg in arg_iter {
s.push_str(", ");
s.push_str(&arg.into_tokens().to_string());
}
s.push(')');
s
}
proc_macro_expr_impl! {
pub fn gprint_impl(input: &str) -> String {
_print_impl(input, "print!")
}
}
And tried using this macro,
fn main() {
let a = 0;
gprint!(a);
}
error occured:
error[E0425]: cannot find value `a` in this scope
Why?
I have a method that can be summed up to look like this:
func apply(username: String, email: String, password: String,
onDone: #escaping (_ error: Error?) -> ())
{
//Do async stuff
do
{
try asyncGood()
onDone(nil)
return
}
catch
{
onDone(error)
return
}
}
What's the difference between doing:
return onDone(error)
versus
onDone(error)
return
?
Does it just save an extra line of code? I don't see any difference between the two. Am I missing some fundamental aspect of asynchronous Swift programming?
In your opinion, should I always try to condense everything down such that onDone(...) only gets called once at the end?
Semantically, both cases are the same. You are basically saying:
return ()
Your method is declared to return (), and since the onDone closure also returns a (), you can say return onDone(error). The return types match.
However, I find writing them in 2 separate lines more readable:
// This clearly shows that you are doing 2 separate things
onDone(error) // call the completion handler
return // return
Or even omit the return!
onDone(error)
// there will be an implicit return at the end of the method.
Both are same. apply function return type is Void and onDone closure return type is also Void. So both are same.
return onDone(error)
or
onDone(error)
return
or you can just ignore return because return type is Void
onDone(error)
There is no difference. In fact, there is no need for return keyword at all.
For swift all the following declaration is equivalent:
func doNothing() {
}
func doNothing2() -> Void {
}
func doNothing3() -> () {
}
func doNothing4() {
return ()
}
func doNothing5() -> Void {
return ()
}
When you return () you return nothing. No return is exactly the same as return nothing. Functions returning Void may be equivalently used as following
doNothing()
var result = doNothing()
More, Void can also be used as a type parameter which is a very powerful feature:
func genericCall<T>(_ f: () -> T) -> T {
return f()
}
var result1 = genericCall { print("test") } // result1 is Void
var result2 = genericCall { return 5 } // result2 is Int
Answering your initial question, I would suggest to omit return at all
func doStuffAsync(_ callback: #escaping (Error?) -> Void) {
// Just an example. Could be any other async call.
DispatchQueue.main.async {
do {
try doStuff()
callback(nil)
}
catch {
callback(error)
}
}
}
I want to write a macro to define something like below:
let FOO: String = "FOO".to_string();
It is possible for me to have a macro:
macro_rules! my_macro {
($name: ident, $val: expr) => {
let $name: String = $val.to_string();
}
}
and use it as my_macro!(FOO, "FOO");
However, this is a bit redundant. I expect to have something like my_macro!(FOO), and it can expand and use the $name as identifier, but also in the string value.
You want stringify!:
macro_rules! str_var {
($name:ident) => {
let $name = String::from(stringify!($name));
};
}
fn main() {
str_var!(foo);
println!("foo: {:?}", foo);
}
I have some generic type class but no instance of object to test. What I would like to do is to alter the behavior of the function according to the runtime type.
class MyGenericUtility<SomeGenericClass> {
func myFunction() {
// so far I have tested "is", "==" and "==="
if SomeGenericClass is SomeRealClass {
println("some special stuff there")
}
println("some generic stuff as the name tells")
}
}
You can compare the class type, using SomeGenericClass.self == SomeRealClass.self as,
class MyGenericUtility<SomeGenericClass> {
func myFunction() {
if SomeGenericClass.self == SomeRealClass.self {
print("SomeRealClass stuffs")
} else if SomeGenericClass.self == String.self {
print("String stuffs")
}
}
}
let someRealUtility = MyGenericUtility<SomeRealClass>()
someRealUtility.myFunction()
let stringUtility = MyGenericUtility<String>()
stringUtility.myFunction()
Rather than testing at runtime, you should generally handle this at compile time with constrained extensions (this assumes Swift 2). Doing it this way avoids any need to do unsafe as! casting when you need to access type-specific parts of the instance.
class MyGenericUtility<SomeGenericClass> {
}
// Special handling for `SomeRealClass`
extension MyGenericUtility where SomeGenericClass: SomeRealClass {
func myFunction() {
print("SomeRealClass stuffs")
}
}
// Default handling for any unspecified class
extension MyGenericUtility {
func myFunction() {
print("Other stuffs")
}
}
let someRealUtility = MyGenericUtility<SomeRealClass>()
someRealUtility.myFunction()
let stringUtility = MyGenericUtility<String>()
stringUtility.myFunction()
Note that this is based on inheritance, not equality, so any subclass of SomeRealClass would get the SomeRealClass behavior.
You can't use the generic type directly, you need to use a property of that type when comparing with "is".
class MyGenericUtility<T> {
var a: T
func myFunction() {
if a is Int {
println("some special stuff there")
}
println("some generic stuff as the name tells")
}
init(value: T) {
a = value
}
}
let test = MyGenericUtility(value: 5)
test.myFunction()
// Output: some special stuff there
// some generic stuff as the name tells
let test2 = MyGenericUtility(value: "foo")
test2.myFunction()
// Output: some generic stuff as the name tells