I have some code that iterates over objects and uses an async method on each of them sequentially before doing something with the results. I'd like to change it so that the async method calls are joined into a single future before being executed. The important bit below is in HolderStruct::add_squares. My current code looks like this:
use anyhow::Result;
struct AsyncMethodStruct {
value: u64
}
impl AsyncMethodStruct {
fn new(value: u64) -> Self {
AsyncMethodStruct {
value
}
}
async fn get_square(&self) -> Result<u64> {
Ok(self.value * self.value)
}
}
struct HolderStruct {
async_structs: Vec<AsyncMethodStruct>
}
impl HolderStruct {
fn new(async_structs: Vec<AsyncMethodStruct>) -> Self {
HolderStruct {
async_structs
}
}
async fn add_squares(&self) -> Result<u64> {
let mut squares = Vec::with_capacity(self.async_structs.len());
for async_struct in self.async_structs.iter() {
squares.push(async_struct.get_square().await?);
}
let mut sum = 0;
for square in squares.iter() {
sum += square;
}
return Ok(sum);
}
}
I'd like to change HolderStruct::add_squares to something like this:
use futures::future::join_all;
// [...]
impl HolderStruct {
async fn add_squares(&self) -> Result<u64> {
let mut square_futures = Vec::with_capacity(self.async_structs.len());
for async_struct in self.async_structs.iter() {
square_futures.push(async_struct.get_square());
}
let square_results = join_all(square_futures).await;
let mut sum = 0;
for square_result in square_results.iter() {
sum += square_result?;
}
return Ok(sum);
}
}
However, the compiler gives me this error using the above:
error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
--> src/main.rs:46:20
|
46 | sum += square_result?;
| ^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `&std::result::Result<u64, anyhow::Error>`
|
= help: the trait `std::ops::Try` is not implemented for `&std::result::Result<u64, anyhow::Error>`
= note: required by `std::ops::Try::into_result`
How would I change the code to not have this error?
for square_result in square_results.iter()
Lose the iter() call here.
for square_result in square_results
You seem to be under impression that calling iter() is mandatory to iterate over a collection. Actually, anything that implements IntoIterator can be used in a for loop.
Calling iter() on a Vec<T> derefs to slice (&[T]) and yields an iterator over references to the vectors elements. The ? operator tries to take the value out of the Result, but that is only possible if you own the Result rather than just have a reference to it.
However, if you simply use a vector itself in a for statement, it will use the IntoIterator implementation for Vec<T> which will yield items of type T rather than &T.
square_results.into_iter() does the same thing, albeit more verbosely. It is mostly useful when using iterators in a functional style, a la vector.into_iter().map(|x| x + 1).collect().
This question already has answers here:
How do I print in Rust the type of a variable?
(17 answers)
Closed 4 years ago.
For example:
struct ABC;
impl ABC {
fn some_method(&self) -> &str {
// return the name of its struct -> "ABC"
}
}
I'm writing Python extensions and I need a way to return the current struct's name for its repr method. In Python, I can get this using self.__class__.__name__. Is there anything similar in Rust?
It's possible with nightly and the core_intrinsics feature:
#![feature(core_intrinsics)]
use std::intrinsics::type_name;
struct ABC;
impl ABC {
fn some_method(&self) -> &'static str {
unsafe { type_name::<Self>() }
}
}
fn main() {
println!("{}", ABC.some_method()); // ABC
}
I have a static func that creates a dictionary from a bunch of enums in a struct.
It looks like this:
// Struct section starts here
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
// Must use static for non-instance methods
static func createDeck() -> [Card] {
var deck = [Card]()
var n = 1
while let rank = Rank.fromRaw(n) {
var m = 1
while let suit = Suit.fromRaw(m) {
deck += Card(rank: rank, suit: suit)
m++
}
n++
}
return deck
}
}
The output is a nice bunch of enums when I call Card.createDeck() that look like this
{(Enum Value), (Enum Value)}
...
Lots of this
...
{(Enum Value), (Enum Value)}
I can even see the wrapped values if I do this:
for n in deck {
println(n)
}
Which nets me lots of this:
_TtV13__lldb_expr_04Card
I can't figure out how to unwrap these enums; please can someone help me?
Thanks
First of all: you have an array of card, not a dictionary.
Second: items in the array are not optionals hence no need to unwrap anything.
In for loop you can access card description:
for n in deck {
println(n.simpleDescription())
}
I'm wondering if I can somehow use an x, y pair as the key to my dictionary
let activeSquares = Dictionary <(x: Int, y: Int), SKShapeNode>()
But I get the error:
Cannot convert the expression's type '<<error type>>' to type '$T1'
and the error:
Type '(x: Int, y: Int)?' does not conform to protocol 'Hashable'
So.. how can we make it conform?
The definition for Dictionary is struct Dictionary<KeyType : Hashable, ValueType> : ..., i.e. the type of the key must conform to the protocol Hashable. But the language guide tells us that protocols can be adopted by classes, structs and enums, i.e. not by tuples. Therefore, tuples cannot be used as Dictionary keys.
A workaround would be defining a hashable struct type containing two Ints (or whatever you want to put in your tuple).
As mentioned in the answer above, it is not possible. But you can wrap tuple into generic structure with Hashable protocol as a workaround:
struct Two<T:Hashable,U:Hashable> : Hashable {
let values : (T, U)
var hashValue : Int {
get {
let (a,b) = values
return a.hashValue &* 31 &+ b.hashValue
}
}
}
// comparison function for conforming to Equatable protocol
func ==<T:Hashable,U:Hashable>(lhs: Two<T,U>, rhs: Two<T,U>) -> Bool {
return lhs.values == rhs.values
}
// usage:
let pair = Two(values:("C","D"))
var pairMap = Dictionary<Two<String,String>,String>()
pairMap[pair] = "A"
Unfortunately, as of Swift 4.2 the standard library still doesn't provide conditional conformance to Hashable for tuples and this is not considered valid code by the compiler:
extension (T1, T2): Hashable where T1: Hashable, T2: Hashable {
// potential generic `Hashable` implementation here..
}
In addition, structs, classes and enums having tuples as their fields won't get Hashable automatically synthesized.
While other answers suggested using arrays instead of tuples, this would cause inefficiencies. A tuple is a very simple structure that can be easily optimized due to the fact that the number and types of elements is known at compile-time. An Array instance almost always preallocates more contiguous memory to accommodate for potential elements to be added. Besides, using Array type forces you to either make item types the same or to use type erasure. That is, if you don't care about inefficiency (Int, Int) could be stored in [Int], but (String, Int) would need something like [Any].
The workaround that I found relies on the fact that Hashable does synthesize automatically for fields stored separately, so this code works even without manually adding Hashable and Equatable implementations like in Marek Gregor's answer:
struct Pair<T: Hashable, U: Hashable>: Hashable {
let first: T
let second: U
}
No need special code or magic numbers to implement Hashable
Hashable in Swift 4.2:
struct PairKey: Hashable {
let first: UInt
let second: UInt
func hash(into hasher: inout Hasher) {
hasher.combine(self.first)
hasher.combine(self.second)
}
static func ==(lhs: PairKey, rhs: PairKey) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
}
More info: https://nshipster.com/hashable/
I created this code in an app:
struct Point2D: Hashable{
var x : CGFloat = 0.0
var y : CGFloat = 0.0
var hashValue: Int {
return "(\(x),\(y))".hashValue
}
static func == (lhs: Point2D, rhs: Point2D) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
struct Point3D: Hashable{
var x : CGFloat = 0.0
var y : CGFloat = 0.0
var z : CGFloat = 0.0
var hashValue: Int {
return "(\(x),\(y),\(z))".hashValue
}
static func == (lhs: Point3D, rhs: Point3D) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z
}
}
var map : [Point2D : Point3D] = [:]
map.updateValue(Point3D(x: 10.0, y: 20.0,z:0), forKey: Point2D(x: 10.0,
y: 20.0))
let p = map[Point2D(x: 10.0, y: 20.0)]!
If you don't mind a bit of inefficiency, you can easily convert your tuple to a string and then use that for the dictionary key...
var dict = Dictionary<String, SKShapeNode>()
let tup = (3,4)
let key:String = "\(tup)"
dict[key] = ...
You can't yet in Swift 5.3.2, But you can use an Array instead of tuple:
var dictionary: Dictionary<[Int], Any> = [:]
And usage is simple:
dictionary[[1,2]] = "hi"
dictionary[[2,2]] = "bye"
Also it supports any dimentions:
dictionary[[1,2,3,4,5,6]] = "Interstellar"
I suggest to implement structure and use solution similar to boost::hash_combine.
Here is what I use:
struct Point2: Hashable {
var x:Double
var y:Double
public var hashValue: Int {
var seed = UInt(0)
hash_combine(seed: &seed, value: UInt(bitPattern: x.hashValue))
hash_combine(seed: &seed, value: UInt(bitPattern: y.hashValue))
return Int(bitPattern: seed)
}
static func ==(lhs: Point2, rhs: Point2) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
func hash_combine(seed: inout UInt, value: UInt) {
let tmp = value &+ 0x9e3779b97f4a7c15 &+ (seed << 6) &+ (seed >> 2)
seed ^= tmp
}
It's much faster then using string for hash value.
If you want to know more about magic number.
Add extension file to project (View on gist.github.com):
extension Dictionary where Key == Int64, Value == SKNode {
func int64key(_ key: (Int32, Int32)) -> Int64 {
return (Int64(key.0) << 32) | Int64(key.1)
}
subscript(_ key: (Int32, Int32)) -> SKNode? {
get {
return self[int64key(key)]
}
set(newValue) {
self[int64key(key)] = newValue
}
}
}
Declaration:
var dictionary: [Int64 : SKNode] = [:]
Use:
var dictionary: [Int64 : SKNode] = [:]
dictionary[(0,1)] = SKNode()
dictionary[(1,0)] = SKNode()
Or just use Arrays instead. I was trying to do the following code:
let parsed:Dictionary<(Duration, Duration), [ValveSpan]> = Dictionary(grouping: cut) { span in (span.begin, span.end) }
Which led me to this post. After reading through these and being disappointed (because if they can synthesize Equatable and Hashable by just adopting the protocol without doing anything, they should be able to do it for tuples, no?), I suddenly realized, just use Arrays then. No clue how efficient it is, but this change works just fine:
let parsed:Dictionary<[Duration], [ValveSpan]> = Dictionary(grouping: cut) { span in [span.begin, span.end] }
My more general question becomes "so why aren't tuples first class structs like arrays are then? Python pulled it off (duck and run)."
struct Pair<T:Hashable> : Hashable {
let values : (T, T)
init(_ a: T, _ b: T) {
values = (a, b)
}
static func == (lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lhs.values == rhs.values
}
func hash(into hasher: inout Hasher) {
let (a, b) = values
hasher.combine(a)
hasher.combine(b)
}
}
let myPair = Pair(3, 4)
let myPairs: Set<Pair<Int>> = set()
myPairs.update(myPair)
Suppose, I am writing a minesweeper game, and i have a struct to hold the game field, that contains a 2D array with mines. Suppose, i want to initialize it with some mines. Is there a way to say gameField GameField = new(GameField, 30), similar to what i'd do in java?
Here is some code to illustrate my point:
type GameField struct {
field [20][20] int
}
func (this *GameField) scatterMines(numberOfMines int) {
//some logic to place the numberOfMines mines randomly
}
What i want is to call an initializer and have that scatterMines func executed automatically.
A pattern I've seen in Go structs is a corresponding NewXxx method (e.g., image pkg):
type GameField struct {
field [20][20] int
}
func NewGameField(numberOfMines int) *GameField {
g := new(GameField)
//some logic to place the numberOfMines mines randomly
//...
return g
}
func main() {
g := NewGameField(30)
//...
}
Go objects have no constructors, so there is no way to have scatterMines function executed automatically at variable initialization. You need to call the method explicitly:
var GameField g
g.scatterMines(30)
See also http://golang.org/ref/spec#The_zero_value.