同时持有不同类型的集合 传统上,我已经用C++和java编程了,现在我开始学习Ruby。

同时持有不同类型的集合 传统上,我已经用C++和java编程了,现在我开始学习Ruby。,c++,ruby,C++,Ruby,那么,我的问题是,像ruby这样的语言如何在内部实现它们的数组和散列数据结构,使它们能够同时保存任何类型?我知道在Java中,每个类都是从object派生的这一事实可能是实现这一点的一种方法,但我想知道是否还有其他方法。例如,在C++中,如果我想实现一个动态数组,它可以同时保存多种类型的值(不相关),那么我怎么做? 澄清一下,我不是指泛型编程或模板,因为它们只是为类型创建一个新的集合接口。我指的是这样一种结构: array=[1,“hello”,someClass]; 有很多方法可以做到这一点:

那么,我的问题是,像ruby这样的语言如何在内部实现它们的数组和散列数据结构,使它们能够同时保存任何类型?我知道在Java中,每个类都是从object派生的这一事实可能是实现这一点的一种方法,但我想知道是否还有其他方法。例如,在C++中,如果我想实现一个动态数组,它可以同时保存多种类型的值(不相关),那么我怎么做? 澄清一下,我不是指泛型编程或模板,因为它们只是为类型创建一个新的集合接口。我指的是这样一种结构:

array=[1,“hello”,someClass];

有很多方法可以做到这一点:-

您可以为所有元素定义一个公共接口,并为这些元素创建一个容器。例如:

class Common { /* ... */ };  // the common interface.
您可以使用
void*
:-

vector<void*> common;        // this would rather be too low level.
                             // you have to use cast very much.
向量公共;//这将是太低的水平。
//你必须经常使用cast。
我认为最好的方法是使用Any类,比如Boost::Any:-

vector<boost::any> v;
向量v;
您正在寻找一种称为类型擦除的东西。在C++中实现这一点的最简单的方法是:

在这里,我们将三个不同类型的对象(一个
void(*)(
),一个
SomeClass
,以及一些lambda)添加到同一个容器中-我们通过删除类型来完成这一操作。因此,我们仍然可以:

for (auto& func : callbacks) {
    func();
}

这将在三个物体中做正确的事情。。。没有虚拟需要

>P>大多数与C++中创建的<代码>向量 >(或<代码>列表,<代码> DEQu< /COD>等)大致相同,<>代码> Boo::任何< /C> >,或类似的东西。 也就是说,它们基本上在存储在内存中的每种类型的对象上附加一些标记。当它们存储对象时,它们存储标记。当他们读取一个对象时,他们会查看标签以确定该对象的类型。当然,它们也会在内部处理大部分内容,因此您不必编写代码来确定刚刚从集合中检索到的对象类型

如果不清楚:“标签”只是分配给每种类型的唯一编号。如果您正在处理的系统具有基元类型,它通常会为每个基元类型预先分配一个类型号。同样,您创建的每个类都会被分配一个唯一的编号

<>在C++中这样做,通常会创建一个标记的中心注册表。注册类型时,会收到一个唯一的编号,用于标记该类型的对象。当一种语言直接支持这一点时,它会自动注册类型并为每个类型选择唯一标记

虽然这可能是实现这些事情的最常用方法,但它肯定不是唯一的方法。例如,还可以为特定类型指定特定的存储范围。当您分配一个给定类型的对象时,它总是从该类型的地址范围分配的。创建“对象”集合时,实际上并不是存储对象本身,而是存储包含对象地址的内容。由于对象是按地址分隔的,因此您可以根据指针的值确定对象的类型。

在解释器中,ruby值作为指针类型存储,该指针类型指向存储值类和与值相关的任何数据的数据结构。由于指针的大小总是相同的(
sizeof(unsigned long)
通常),这是可能的。要回答C++的问题,C++中不可能在给定内存中的位置来确定对象的类,所以除非你有这样的东西,否则它是不可能的:

enum object_class { STRING, ARRAY, MAP, etc... };

struct TaggedObject {
  enum object_class klass;
  void *value;
}
enum TypeKind { None, Int, Float, String }; // May need a few more?

class TypeBase
{
   protected:
     TypeKind kind;
   public:
     TypeBase(TypeKind k) : kind(k) { }
     virtual ~TypeBase() {};
     TypeKind type() { return kind; }
};


class TypeInt : public TypeBase
{
   private: 
      int value;
   public:
      TypeInt(int v) : value(v), TypeBase(Int) {}
};

class TypeFloat : public TypeBase
{
   private: 
      double value;
   public:
      TypeFloat(double v) : value(v), TypeBase(Float) {}
};

class TypeString : public TypeBase
{
   private: 
      std::string value;
   public:
      TypeString(std::string v) : value(v), TypeBase(String) {}
};

并传递
TaggedObject*
值。这是Ruby在内部做的事情。

其他人已经解释了C++中可以做到这一点的方法。p> 解决这个问题有多种方法。为了回答您关于Ruby等语言如何解决此问题的问题,在不详细介绍Ruby如何解决此问题的情况下,它们使用包含类型信息的结构。例如,我们可以在C++中这样做:< /P>

enum object_class { STRING, ARRAY, MAP, etc... };

struct TaggedObject {
  enum object_class klass;
  void *value;
}
enum TypeKind { None, Int, Float, String }; // May need a few more?

class TypeBase
{
   protected:
     TypeKind kind;
   public:
     TypeBase(TypeKind k) : kind(k) { }
     virtual ~TypeBase() {};
     TypeKind type() { return kind; }
};


class TypeInt : public TypeBase
{
   private: 
      int value;
   public:
      TypeInt(int v) : value(v), TypeBase(Int) {}
};

class TypeFloat : public TypeBase
{
   private: 
      double value;
   public:
      TypeFloat(double v) : value(v), TypeBase(Float) {}
};

class TypeString : public TypeBase
{
   private: 
      std::string value;
   public:
      TypeString(std::string v) : value(v), TypeBase(String) {}
};
(为了使它有用,我们可能需要更多的
TypeXxx
类方法,但我不想再输入一个小时了……;)

然后在某个地方,它决定了类型,例如

Token t = getNextToken();
TypeBase *ty;
if (t.type == IntegerToken)
{
   ty = new(TypeInt(stoi(t.str));
}
else if (t.type == FloatToken)
{
   ty = new(TypeFloat(stod(t.str));
}
else if (t.type == StringToken)
{
   ty = new(TypeString(t.str));
}
当然,我们还需要处理变量和各种其他场景,但其本质是语言可以跟踪(有时会改变)存储的值

Ruby、PHP、Python等通用类别中的大多数语言都有这种机制,所有变量都以某种间接方式存储。以上只是一种可能的解决方案,我可以想出至少六种其他方法来实现这一点,但它们是“将数据与类型信息一起存储”主题的变体


(顺便说一句,
boost::any
也或多或少地执行了上述操作)

在Ruby中,答案相当简单:数组不包含不同类型的值,它们都是相同类型的。它们都是物体

Ruby是动态类型化的,静态约束数组只保存相同类型的元素的想法根本没有意义

对于静态类型语言,问题是,您希望它有多像Ruby?您希望它实际上是动态类型的吗?然后您需要在您的语言中实现一个动态类型(如果它还没有,比如C)♯’s
动态

否则,如果您想要一个静态类型的异构列表,这种东西通常称为
HList
。有一个很好的例子