【问题标题】:Call a method from within class declaration in D从 D 中的类声明中调用方法
【发布时间】:2013-12-06 04:22:51
【问题描述】:

所以,从 Ruby 开始,做这样的事情是一种常见的模式:

class Animal
  class << self
    def type(*args)
      if args.length == 1
        @type = type.first
      else
        @type
      end
    end
  end
end

class Dog < Animal
  type "Mammal"
end

Dog.type # => "Mammal"

但我无法让类似的东西在 D 中工作:

class Animal {
  static string animalType;

  static void type(string type) {
    animalType = type;
  }
}

class Dog : Animal {
  type(cast(string)"Mammal");
}

我得到编译器错误:

Error: unexpected ( in declarator
Error: basic type expected, not cast
Error: found 'cast' when expecting ')'
Error: no identifier for declarator type(int)
Error: semicolon expected following function declaration
Error: Declaration expected, not '('

这可能吗?

【问题讨论】:

  • 您确定您的 Ruby 代码有效吗?我喜欢 Ruby,但你不必从 Animal 继承吗?换句话说,我认为您的代码中需要class Dog &lt; Animal。对吗?
  • 你是对的,我的 Ruby 中有一个错误。

标签: d


【解决方案1】:

this 是类构造函数,在派生类 (Dog) 中可以使用super(...) 调用它

import std.stdio;

class Animal {
  string animalType;

  this(string type) {
    animalType = type;
  }
}

class Dog : Animal {
  this () {
    super("Mammal");
  }
}

void main () {
    auto d = new Dog();
    writeln(d.animalType);  // Mammal

    auto a = new Animal("Xyz");
    writeln(a.animalType);  // Xyz
}

【讨论】:

  • 所以不可能在班级级别上设置它?您必须实例化 Dog 才能获得其类型?
  • 类变量也称为“静态”。你可以像 class Animal { static string animalType; } ...然后像 Animal.animalType = "abc"; 一样访问它们无需创建 Animal 实例。值 'abc' 将在 Animal 或派生类 (Dog) 的所有实例之间共享。
  • 这是否意味着,我会在 Dog 类中这样做 class Dog { static string animalType = "Mammal"; },也许在 Seagull 类中我会这样做 class Seagull { static string animalType = "Bird"; }
  • @jaredonline - 否。静态变量在所有类实例(对象)和派生对象之间共享。每个都有相同的价值。如果您想在每个对象中具有不同的值,请不要使用静态。但是对于我觉得你想要实现的东西,使用 interface: interface IAnimal { string animalType(); } 然后在像 class Dog : IAnimal { string animalType() { return "Mammal"; } } 这样的类中实现它 - 这样你可以对每种类型都有相同的行为(即,不像非静态 - 对于每个实例,不像静态- 适用于所有实例和类型)
  • 感谢您的信息。我认为现在有道理 [=
【解决方案2】:

您确定您的 Ruby 代码有效吗?我可能从未做过任何 Ruby 编程,所以我不确定我要问什么。 - 你不必从Animal继承吗?换句话说,我认为您的代码中需要class Dog &lt; Animal。对?如果是这种情况,那么您的 D 代码与您的 Ruby 代码不同。在您的 D 代码中,type() 方法是 static

Ruby 代码可以这样翻译成 D:

import std.stdio;

class Animal {
    private string _type;

    public void type(string arg) @property {
        _type = arg;
    } // type() method

    public string type() @property {
        return _type;
    }

    public override string toString() {
        return "type: " ~ _type;
    }
} // Animal class

class Dog : Animal {
    this() {
        type("Mammal");
    } // Dog constructor (default)
} // Dog class

void main() {
    auto dog = new Dog;
    writeln(dog);
}

这是一个 DPaste,您可以使用它:http://dpaste.dzfl.pl/ae83be11

【讨论】:

  • 你是对的!我的 Ruby 缺少继承,它应该是 Dog &lt; Animal
【解决方案3】:

不,这是不可能的。呃,我撒谎,但不是真的。

class Animal {
  static string animalType;

  static int type(string type) {
    animalType = type;
    return 0;
  }
}

class Dog : Animal {
  enum r = Animal.type("Mammal");
}
test.d(5): Error: animalType cannot be modified at compile time

接着你的第二个问题:“所以不可能在类级别上设置它?你必须实例化 Dog 才能获得它的类型?”

没有:

mixin template AnimalType(string t) {
    enum animalType = t;
    override string type() {
        return animalType;
    }
}
abstract class Animal {
    string type();
}

class Dog : Animal {
    mixin AnimalType!"Mammal";
}

void main() {
    assert(Dog.animalType == "Mammal");
    Animal snake = new Dog();
    assert(snake.type == "Mammal");
}

【讨论】:

  • 如果分配给变量而不是枚举,它将起作用。
  • @МихаилСтрашун,不。 D 不是 C#/Java。那些对变量的赋值仍然需要在编译时知道。我以为我会得到一个不同的错误,但它是同一个。
  • 这是来自 D1 的编译器错误/遗留行为,将在几个版本中缓慢改变。在静态构造函数中分配可以用作临时解决方法。 (按规范编译器可能会在此处进行编译时评估,但不是强制性的)
  • @МихаилСтрашун,很酷,但它仍然无法满足 jaredonline 的要求。
  • 实际上,忽略这一点,尽管r 是可变的,而不是带有初始化程序的聚合字段,但我有一些奇怪的原因。这确实需要是编译时值(初始化器,而不是字段)以符合T.init 保证。所以在这种情况下,静态构造函数是唯一的选择。
猜你喜欢
  • 2020-08-06
  • 2015-07-10
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多