This is the rust warp example for newbies to get started. It's supposed to be "super easy" but it currently makes me feel super stupid.
use warp::Filter;
#[tokio::main]
async fn main() {
// GET /hello/warp => 200 OK with body "Hello, warp!"
let hello = warp::path!("hello" / String)
.map(|name| format!("Hello, {}!", name));
warp::serve(hello)
.run(([127, 0, 0, 1], 3030))
.await;
}
I'd like to run this on the root path, defined like this:
let hello = warp::path!("" /).map(|| "Hello!");
But the macro doesn't take an empty path name. I get the error:
no rules expected the token `start`
I guess "super easy" means different things to different people.
Addendum:
So, I tried the solution mentioned by Ivan C (comment below) from here It doesn't work either. Applying that solution
let hello = warp::path::end().map(|name| format!("Hello"));
Leads in turn to this error message:
[rustc E0599] [E] no method named `map` found for opaque type `impl warp::Filter+std::marker::Copy` in the current scope
method not found in `impl warp::Filter+std::marker::Copy`
note: the method `map` exists but the following trait bounds were not
satisfied: `impl warp::Filter+std::marker::Copy: std::iter::Iterator`
Seems like routing with warp paths only works if one does not need a root route, which is simply a show stopper.
This does not compile:
let hello = warp::path::end()
.map(|name| format!("Hello"));
Because where would the name argument in your closure be coming from if you're no longer dynamically matching on any part of the route path anymore? If you remove the unused name argument, and the format! is also unnecessary, then it works:
use warp::Filter;
#[tokio::main]
async fn main() {
let hello = warp::path::end()
.map(|| "Hello");
warp::serve(hello)
.run(([127, 0, 0, 1], 3030))
.await;
}
Visiting http://127.0.0.1:3030 now produces Hello.
Related
I've found this function in an assemblyscript project for a NEAR contract:
export function assert_single_promise_success(): void {
const x = ContractPromise.getResults()
assert(x.length == 1, "Expected exactly one promise result")
assert(x[0].succeeded, "Expected PromiseStatus to be successful")
}
What does ContractPromise.getResults() do exactly? How should implement the same thing in rust?
here is something similar in Rust from one of the examples in the SDK repo
require!(env::promise_results_count() == 2);
let data0: Vec<u8> = match env::promise_result(0) {
PromiseResult::Successful(x) => x,
_ => env::panic_str("Promise with index 0 failed"),
};
I'm going to give an answer, comments taken directly from the implementation of ContractPromise.getResults(), which can be found here. The implementation also has an example on how to use the function, which may be useful.
Method to receive async (one or multiple) results from the remote
contract in the callback.
#returns An array of results based on the number of promises the
callback was created on. If the callback using then was scheduled
only on one result, then one result will be returned.
I have code similar to this:
pub trait WorldImpl {
fn new(size: (usize, usize), seed: u32) -> World;
fn three() -> bool;
fn other() -> bool;
fn non_self_methods() -> bool;
}
pub type World = Vec<Vec<UnitOfSpace>>;
// I'm doing this because I want a SPECIAL version of Vec<Vec<UnitOfSpace>>, so I can treat it like a struct but have it be a normal type underneath.
impl WorldImpl for World {
fn new(size: (usize, usize), seed: u32) -> World {
// Code
vec![/* vector stuff */]
}
// Implement other three methods
}
let w = World::new((120, 120), /* seed from UNIX_EPOCH stuff */);
And I get this error, which is clearly wrong:
error[E0061]: this function takes 0 parameters but 2 parameters were supplied
--> src/main.rs:28:28
|
28 | let world = World::new((120 as usize, 120 as usize),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 0 parameters
I'm thinking two things:
This is not idiomatic and Rust was never meant to be used this way. In this case, I need to know how to really do this.
It's a stupid error that I'm missing.
When I try similar code to the above on the playground, it works just fine, no errors. I have not found any information on any errors like this anywhere else, so I'll not be surprised to find out I'm just using the language wrong. I have no particular attachment to any of my code, so please tell me what the idiom is for this!
What you are trying to do doesn't quite make sense. You have made World a type alias for Vec<Vec<UnitOfSpace>>, so they are completely interchangeable - the implementations you add for one will apply to the other and vice versa.
If you want to treat this type differently then wrap it in a newtype:
struct World(Vec<Vec<UnitOfSpace>>);
This is now a distinct type from Vec<Vec<UnitOfSpace>>, but with zero runtime overhead.
Your actual error is because you have added a method called new to World as part of its implementation of WorldImpl, but World is a Vec which already has a new method (with zero args!).
Your type World is an alias for Vec<Vec<UnitOfSpace>>. Vec<T> provides an inherent associated function called new that takes no parameters. The compiler prefers selecting inherent associated functions to associated functions defined in traits, thus it selects the inherent new with no parameters instead of your own new that takes 2 parameters.
Here are a few options to solve this:
Invoke the trait's associated function explicitly:
let w = <World as WorldImpl>::new((120, 120), /* seed from UNIX_EPOCH stuff */);
Make World a newtype (struct World(Vec<Vec<UnitOfSpace>>);), which will let you define inherent associated functions (but then Vec's inherent methods won't be available on World).
Rename WorldImpl::new to a name that is not used by an inherent associated function on Vec.
I'm having trouble converting optional input String to Int in order to do calculations on it.
let odoField = UITextField() // allows entry of text to iOS field
odoField.text = "12500" // simulated input
let odoString = odoField.text
// now here is where I get trouble...
if let odoInt = odoString.toInt() {
distance = Double(odoInt)
}
Apparently the toInt suffix is no longer part of Swift. I have tried the following:
if let odoInt = Int(odoString)() {
But then I get the error "Optional type String? is not unwrapped" and a suggestion to put a ! or ?, as in:
if let odoInt = Int(odoString!)() {
But then I STILL get the euro about unwrapping, with the suggestion that I add yet another !, then when I do that, another error that I get rid of the parens, like this:
if let odoInt = Int(odoString!)! {
And then I get ANOTHER error that "Initializer for conditional binding must have Optional type, not 'Int'."
I'm trying to create conditional unwrapping, here.
Help!
First thing to understand is that UITextField.text returns an optional string, so in your code, odoString is of type String?. Also, keep in mind that the Int constructor takes a String, not a String? so you have to unwrap the String? before you can use it. Just putting a ! after the variable (as in Int(odoString!)) will crash your app if the odoString is nil. Better would be something like this:
if let s = odoString, odoInt = Int(s) {
// odoInt is of type Int. It is guaranteed to have a value in this block
}
I've tested Daniel T's answer and it worked.
I have a situation where I want to get the result of a text field back as an optional Int. You can extend this to cover your case using the following code:
let odoInt = odoField.text != nil ? Int(odoField.text!) : nil
if let odoInt = odoInt {
// Use unwrapped odoInt here
}
Another option - for a more compact solution - is to use a flatMap:
let number = odoString.flatMap { Double($0) } ?? 0.0
In fact, it appears that the answer in Swift 2 (Xcode 7 beta 6) is simpler than anything above. The code does not choke on a nil value for odoString when I do e.g. the following:
if let odoInt = Int(odoString!) {
distance = Double(odoInt)
}
I therefore surmise, barring deeper knowledge to the contrary, that the compiler does treat this as "if the statement is True (the right side is valid), then define and initialize the variable, and continue with execution." I welcome further feedback. This does render unnecessary a lot of the extra code that is suggested above.
I have a strange issue (which I can overcome however I would like to get a proper understanding of my error).
I have a small random number generator function which I use often:
func ranNum(low: Int, high:Int) -> UInt32 {
var result = arc4random_uniform(UInt32((high+1)-low)) + low
return result
}
When I use this in XCode playgrounds it works just fine if I pass in something like:
ranNum(1, 10)
However, in a regular Swift file it generates the error message : Missing argument label 'hi:' in call. Now I can overcome this by calling the function this way:
ranNum(1, hi:10)
Apart from it just being a little harder to read, it just isn't making sense why it works in Playgrounds but also why it requires only the 2nd argument label and not both. Any help as to what I am not understandinh would be greatly appreciated.
That's called external parameter name, and by default:
global functions: don't have implicit external names
class/struct methods: external names are automatically defined for all parameters after the first
initializers: external names are automatically defined for all parameters
If not explicitly specified, external names take the same name as the local parameter.
You can override that by prefixing a local parameter name with _. In your case:
func ranNum(low: Int, _ high:Int) -> UInt32 {
...
}
You mentioned that in playground calling the function works without any external parameter name - I may argue that:
in playground you have that function as a global function
in other tests, that function is a class/struct method
Am I right?
I've always found the package.New() syntax in go rather awkward to work with.
The suggestion is that if a package holds only a single type, using package.New() to create an instance; if multiple types exist, using package.NewBlah().
http://golang.org/doc/effective_go.html#package-names
However, this approach falls down if you if you have an existing package with a New() api, adding a new external type to the package breaks the api, because you must now rename this NewFoo(). Now you have to go and change anything that uses New(), which is deeply irritating.
...and I'm just discontent with the aesthetic of writing this:
import "other"
import "bar"
import "foo"
o := other.New() // <-- Weird, what type am I getting? No idea.
x := bar.New()
y := foo.NewFoo() // <-- Awkward, makes constructor naming look inconsistent
z := foo.NewBar()
So, recently I've been using this pattern instead:
x := foo.Foo{}.New() // <-- Immediately obvious I'm getting a Foo
y := foo.Bar{}.New() // <-- Only an additional 3 characters on NewBar{}
o := other.Foo{}.New() // <-- Consistent across all packages, no breakage on update
Where the module is defined something like this:
package foo
type Foo struct {
x int
}
func (s Foo) New() *Foo {
// Normal init stuff here
return &s // <-- Edit: notice the single instance is returned
}
type Bar struct {
}
func (Bar) New() *Bar {
return &Bar{} // <-- Edit: Bad, results in double alloc. Not like this.
}
Godoc seems to work fine with it, and it seems more obvious and consistent to me, without additional verbosity.
So, question: Is there any tangible downside to this?
Yes, it has a downside. This approach may generate unnecessary garbage - depending on how good the optimization of a specific Go compiler implementation is.
It's not terribly idiomatic and may if done badly create excess garbage as you note. Essentially you are just creating an Init method for your object. I don't use a lot of constructors myself tending to prefer having valid zero values for my objects and only using a constructor if that doesn't hold true.
In your case I think I'd just stop calling the method new and instead call it Init or Setup to better reflect what it's doing. That would avoid giving people the wrong idea about what it's doing.
Edit:
I should have been more detailed here. Calling the method Init or Setup and then using it on a Zero Value would better reflect what is going on to the consumer. eg
f := &foo{}
f.Init()
This avoids the excess garbage and gives you an initializer method as you describe.