为了能够在 Java 中迭代对象,它需要实现 Iterable。这又需要一个名为iterator() 的成员函数,它返回Iterator 的合适实现。
从您的问题来看,您是否在地图中使用了哪些类型以及您是否希望能够迭代对(就像在 C++ 中那样)、键或值,还不是很清楚。三种变体的解决方案基本相似,我在下面的示例中选择了值。
首先,我用来测试的 SWIG 接口文件的序言:
%module test
%include "std_string.i"
%include "std_map.i"
为了实现可迭代映射,我在 SWIG 接口文件中声明、定义和包装了另一个类。这个类,MapIterator 为我们实现了Iterator 接口。它是 Java 和封装的 C++ 的混合体,其中一个比另一个更容易编写。首先是一些 Java,一个类型映射,它给出了它实现的接口,然后是 Iterable 接口所需的三个方法中的两个,作为一个类型映射给出:
%typemap(javainterfaces) MapIterator "java.util.Iterator<String>"
%typemap(javacode) MapIterator %{
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public String next() throws java.util.NoSuchElementException {
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
return nextImpl();
}
%}
然后我们提供MapIterator 的C++ 部分,除了next() 的异常抛出部分和迭代器所需的状态(以std::map 自己的@987654332 表示@)。
%javamethodmodifiers MapIterator::nextImpl "private";
%inline %{
struct MapIterator {
typedef std::map<int,std::string> map_t;
MapIterator(const map_t& m) : it(m.begin()), map(m) {}
bool hasNext() const {
return it != map.end();
}
const std::string& nextImpl() {
const std::pair<int,std::string>& ret = *it++;
return ret.second;
}
private:
map_t::const_iterator it;
const map_t& map;
};
%}
最后,我们需要告诉 SWIG,我们正在包装的 std::map 实现了 Iterable 接口,并提供了一个额外的成员函数来包装 std::map,它返回了 MapIterator 类的新实例。刚刚写的:
%typemap(javainterfaces) std::map<int,std::string> "Iterable<String>"
%newobject std::map<int,std::string>::iterator() const;
%extend std::map<int,std::string> {
MapIterator *iterator() const {
return new MapIterator(*$self);
}
}
%template(MyMap) std::map<int,std::string>;
这可能更通用,例如使用宏来隐藏地图的类型,这样如果您有多个地图,只需像使用%template 一样为适当的地图“调用”宏。
原始类型的映射也有一点复杂 - 您需要安排 Java 端使用 Double/Integer 而不是 double/int(我相信自动装箱是术语) ,除非您已经决定包装对,在这种情况下,您可以使用原始成员制作一对。