what happened when pass a method to iterator method
Here's what works. Explanation below.
class String
def rettwo
self + self
end
end
def a_simple_method &proc
proc.call('a')
end
def a_iterator_method
yield 'b'
end
a_simple_method(&:rettwo) # => "aa"
a_iterator_method(&:rettwo) # => "bb"
The &:
construct is called Symbol#to_proc
. It turns symbol into a proc. This proc expects a receiver as a first argument. The remaining arguments are used to call the proc. You're not passing any arguments, hence the "receiver not given" error.
Here's a demonstration of additional arguments:
class String
def say name
"#{self} #{name}"
end
end
def a_simple_method &proc
proc.call('hello', 'ruby')
end
a_simple_method(&:say) # => "hello ruby"
Here's a definition of Symbol#to_proc from some blog post from 2008. Modern Symbol#to_proc seems to be implemented in C, but this can still help the understanding.
class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end
Passing Iterator to method
Can anyone tell me what I'm doing wrong that it's trying to call the " U save(U entity);" method instead of the " Iterable save(Iterable entities);" method?
Well save(Iterable<U> entities)
clearly isn't valid here, because you have an Iterator<E>
, not an Iterable<E>
. They're different types. Given two method overloads which are both invalid for the arguments that you're trying to pass, the compiler has picked one to complain about... it doesn't really matter much which it says is invalid, IMO.
It's not clear why you're calling iterator()
at all, but you should try just changing your code to:
public void persistLandTiles(List<LandTile> tilesToPersist) {
landTileRepo.save(tilesToPersist);
}
After all, List<E>
extends Iterable<E>
- so this method call will be valid...
How do I pass an iterator I am iterating on to a function?
The for
construct consumes the iterator, and doing what you want using it will be quite tricky (if not impossible, I'm really not sure about that).
However, you can have it working pretty easily by switching to a while let
construct, like this:
fn parse_tokens (tokens: &Vec<char>) {
let mut iter = tokens.iter();
let mut things: Vec<Thing> = vec![];
while let Some(token) = iter.next() {
match token {
&'a' => things.push(take_three(&mut iter)),
&'b' => things.push(take_four(&mut iter)),
_ => {},
}
}
}
Passing vector iterator to a function c++
it
is an iterator object, passing it as-is would mean you're trying to pass an object of type vector<tObj>::iterator
for a function expecting tObj*
, and thus the error.
When you do *it
you'd get the underlying object the iterator is representing and when you apply &
atop that, you get that object's address, which is of type tObj*
which agrees with the function's argument type and thus no error.
Pass iterator as a function parameter
The particular error you get is because you'd need a template template argument:
template<template <typename> class C, typename T>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
T sum( C<T>::iterator begin, C<T>::iterator end )
However, the standard containers typically have more than just one template argument:
template < class T, class Alloc = allocator<T> > class vector
and it is a bit non-trivial to write such function correctly. You could use variadic template arguments, or you could do like the standard library does, and only specialize as much as you really need:
// <algorithm>
namespace std {
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
}
In your case (pretending that your need is not covered by the standard algorithms library already):
template <typename Iterator>
auto sum(Iterator begin, Iterator end)
-> decltype(*begin+*begin) // the type of summing two of them
{
if (begin == end) throw std::logic_error("....");
auto s = *begin;
++begin;
for (; begin != end; ++begin) {
s += *begin;
}
return s;
}
There are some more differences from your original code:
- the new code does not assume a null or a default constructor defined (
T s = null;
) - does not introduce additional iterator (
it
) - uses pre-increment
- throws an exception when begin==end
If you add an init
parameter, you can make it almost noexcept
:
template <typename Iterator, typename T>
T sum(Iterator begin, Iterator end, T init)
{
for (; begin!=end; ++begin)
init += *begin;
return init;
}
But only almost, because init += *begin
could still throw.
If you have such signature, you've by the way reproduced the signature of std::accumulate
.
Passing an iterator and vector to a function
The iterator models a pointer, and it most likely either is one, or contains one which points to the vector or its contents. When you copy it, the copy is in fact a different iterator, but it stores the same value, so it still points to the same thing, just like a pointer would.
Pass iterable as method argument?
You need to pass an Iterable
or one of its subtypes, e.g., List
, Set
, etc. So, you can add the HashMap
to a List
, and pass it:
HashMap<String,Date> items = new HashMap<String, Date>();
items.put("item1", new Date());
items.put("item2", new Date());
List<HashMap<String, Date>> list = new ArrayList<HashMap<String, Date>>();
list.add(items);
testMethod(list, "more", "data");
Note that since the parameter type is Iterable<HashMap<String, Date>>
, you can only pass - List<HashMap...>
or Set<HashMap...>
, etc. You cannot pass a List<Map..>
in it.
Can a iterator change the collection it is iterating over? Java
The Iterator
simply provides an interface into some sort of stream, therefore not only is it perfectly possible for next()
to destroy data in some way, but it's even possible for the data in an Iterator
to be unique and irreplaceable.
We could come up with more direct examples, but an easy one is the Iterator
in DirectoryStream
. While a DirectoryStream
is technically Iterable
, it only allows one Iterator
to be constructed, so if you tried to do the following:
Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
int count = length(stream.iterator());
for (Path entry: stream) {
...
}
}
You would get an exception in the foreach block, because the stream can only be iterated once. So in summary, it is possible for your length()
method to change objects and lose data.
Furthermore, there's no reason an Iterator
has to be associated with some separate data-store. Take for example an answer I gave a few months ago providing a clean way to select n
random numbers. By using an infinite Iterator
we are able to provide, filter, and pass around arbitrarily large amounts of random data lazily, no need to store it all at once, or even compute them until they're needed. Because the Iterator
doesn't back any data structure, querying it is obviously destructive.
Now that said, these examples don't make your method bad. Notice that the Guava library (which everyone should be using) provides an Iterators
class with exactly the behavior you detail above, called size()
to conform with the Collections Framework. The burden is then on the user of such methods to be aware of what sort of data they're working with, and avoid making careless calls such as trying to count the number of results in an Iterator
that they know cannot be replaced.
Related Topics
Bootstrap Modal in Ruby on Rails Not Working
Ruby: Automatically Wrapping Methods in Event Triggers
How to Create an Association Between Two Rails Models
Ruby Selenium Web Driver: How to Count Child Element Nodes of a Specific Node
How to Cancel Evaluating a Required Ruby File? (A.K.A. Top-Level Return)
Omission of Curly Braces for a Hash in an Array
Validating Phone Number in Ruby
Error Requiring Pg Under Rvm with Postgres.App
How to Pass the JavaScript Value as JSON Object to the Controller in Ruby on Rails
Jekyll Liquid - Accessing _Config.Yml Dynamically
How to Create Automatically a Instance of Every Class in a Directory
Copy One Slide from Google Slides into a New Presentation Using API
Ruby 2.1 with Erubis Template Engine
Has_Many and No Method Error Issue
Kaminari Undefined Method 'Total_Pages'
Ruby: Wait for All Threads Completed Using Join and Threadswait.All_Waits - What the Difference
Error While Installing Iconv on Windows by Ruby2.0.0
How to Find the Most Recently Modified Folder in a Directory Using Ruby