锡兰元模型
Ceylon metamodel
我正在研究 Ceylon 并且对它的元模型有疑问。我想创建一些 create some base class 'DataContainer' 允许实例化不可变 classes 与内置 equals-hash 实现:
例如标识符(125,"ab")==标识符(125,"ab")
所以 base class 应该收集所有共享的非变量值并在 'hash' 和 'equals' 方法中使用这些信息。
我写了这段代码:
shared abstract class DataContainer(ClassDeclaration declaration) {
value members = {
for (i in declaration.memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "hash", i.name != "string") i
};
variable Integer? hashCode = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (item in members) {
value thisMember = item.memberGet(this);
value thatMember = item.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => hashCode else (hashCode = calculateHash());
Integer calculateHash() {
variable value result = 0;
for(i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? id, shared String? name) extends DataContainer(`class`) {}
标识符class是DataContainer的客户端。我总体上喜欢这个解决方案,但我必须将 'class' 传递给超级 class 构造函数,因为如果我在 DataContainer 中使用 'class' 它看不到 subclass 的任何成员.
如何在基本 class 方法中获取扩展 class 成员的实际列表?
'this' 之类的东西不起作用...
感谢 Ceylon 社区的人,我找到了解决方案。应该使用 ceylon.language.meta 中的函数 classDeclaration(this) 而不是 'class'.
这是最终代码:
shared abstract class DataContainer() {
variable Integer? _hash = null;
variable ValueDeclaration[]? _members = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (i in members) {
value thisMember = i.memberGet(this);
value thatMember = i.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => _hash else (_hash = calculateHash());
ValueDeclaration[] members => _members else (_members = [
for (i in classDeclaration(this).memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "string", i.name != "hash") i
]);
Integer calculateHash() {
variable Integer result = 0;
for (i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? number, shared String? name) extends DataContainer() {}
除了 Alexander 令人生畏的回答之外,我还冒昧地实现了一个 string
函数,这样您就可以 print(myObj)
并且它呈现得很好:
shared default actual String string {
value s = StringBuilder();
s.append(type(this).declaration.name).append(" { ");
for (i in members) {
value m = i.memberGet(this);
s.append(i.name).append(":");
s.append(if(exists m) then m.string else "<null>");
}
return s.append(" }").string;
}
我正在研究 Ceylon 并且对它的元模型有疑问。我想创建一些 create some base class 'DataContainer' 允许实例化不可变 classes 与内置 equals-hash 实现: 例如标识符(125,"ab")==标识符(125,"ab") 所以 base class 应该收集所有共享的非变量值并在 'hash' 和 'equals' 方法中使用这些信息。 我写了这段代码:
shared abstract class DataContainer(ClassDeclaration declaration) {
value members = {
for (i in declaration.memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "hash", i.name != "string") i
};
variable Integer? hashCode = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (item in members) {
value thisMember = item.memberGet(this);
value thatMember = item.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => hashCode else (hashCode = calculateHash());
Integer calculateHash() {
variable value result = 0;
for(i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? id, shared String? name) extends DataContainer(`class`) {}
标识符class是DataContainer的客户端。我总体上喜欢这个解决方案,但我必须将 'class' 传递给超级 class 构造函数,因为如果我在 DataContainer 中使用 'class' 它看不到 subclass 的任何成员. 如何在基本 class 方法中获取扩展 class 成员的实际列表? 'this' 之类的东西不起作用...
感谢 Ceylon 社区的人,我找到了解决方案。应该使用 ceylon.language.meta 中的函数 classDeclaration(this) 而不是 'class'.
这是最终代码:
shared abstract class DataContainer() {
variable Integer? _hash = null;
variable ValueDeclaration[]? _members = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (i in members) {
value thisMember = i.memberGet(this);
value thatMember = i.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => _hash else (_hash = calculateHash());
ValueDeclaration[] members => _members else (_members = [
for (i in classDeclaration(this).memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "string", i.name != "hash") i
]);
Integer calculateHash() {
variable Integer result = 0;
for (i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? number, shared String? name) extends DataContainer() {}
除了 Alexander 令人生畏的回答之外,我还冒昧地实现了一个 string
函数,这样您就可以 print(myObj)
并且它呈现得很好:
shared default actual String string {
value s = StringBuilder();
s.append(type(this).declaration.name).append(" { ");
for (i in members) {
value m = i.memberGet(this);
s.append(i.name).append(":");
s.append(if(exists m) then m.string else "<null>");
}
return s.append(" }").string;
}