Evet, düşündüm ve benim yanıtımın yanlış olduğuna karar verdim. :)
ÜçgenBölge sınıfının toHash işlevi, noktaların bütün üyelerini göze alamaz. Ama yanlışlık aslında ÜçgenBölge'de değil. Yanlışlık, Nokta'nın toHash işlevinin bulunmamasından kaynaklanıyor. Çünkü eşitlik ve sıra karşılaştırmalarını tanımladığı halde onlarla uyumlu bir toHash işlevi tanımlamamış.
Bunu görmek için yukarıdaki kodlardan oluşan aşağıdaki programı yazdım. 'hatasız' isimli bir version bloğu var; program ancak onu etkinleştirince doğru çalışıyor:
import std.stdio;
import std.random;
import std.string;
import std.conv;
enum Renk { mavi, yeşil, kırmızı };
class Nokta
{
int x;
int y;
Renk renk;
this(int x, int y, Renk renk)
{
this.x = x;
this.y = y;
this.renk = renk;
}
override string toString() const
{
return format("(%s,%s,%s)", x, y, to!string(renk));
}
override const bool opEquals(Object o)
{
auto sağdaki = cast(const Nokta)o;
return (x == sağdaki.x) && (y == sağdaki.y);
}
override const int opCmp(Object o)
{
auto sağdaki = cast(const Nokta)o;
return (x != sağdaki.x
? x - sağdaki.x
: y - sağdaki.y);
}
version (hatasız)
{
override const hash_t toHash()
{
return x + y;
}
} // version hatasız
}
class ÜçgenBölge
{
Nokta[3] noktalar;
this(Nokta bir, Nokta iki, Nokta üç)
{
noktalar = [ bir, iki, üç ];
}
override string toString() const
{
return format("%s", noktalar);
}
override const bool opEquals(Object o)
{
auto sağdaki = cast(const ÜçgenBölge)o;
return noktalar == sağdaki.noktalar;
}
override const int opCmp(Object o)
{
auto sağdaki = cast(const ÜçgenBölge)o;
foreach (i, nokta; noktalar) {
const int karşılaştırma =
nokta.opCmp(sağdaki.noktalar[i]);
if (karşılaştırma != 0) {
return karşılaştırma;
}
}
return 0;
}
override const hash_t toHash()
{
return typeid(noktalar).getHash(&noktalar);
}
}
Nokta merkezdeRenkliNokta()
{
return new Nokta(0, 0, cast(Renk)uniform(0, Renk.max + 1));
}
ÜçgenBölge merkezdeÜçgenBölge()
{
return new ÜçgenBölge(merkezdeRenkliNokta(),
merkezdeRenkliNokta(),
merkezdeRenkliNokta());
}
void main()
{
int[ÜçgenBölge] tablo;
/*
* Tabloya aynı x ve y değerlerine sahip ama rastgele renkli noktalar
* yerleştiriyoruz
*/
foreach (sayaç; 0 .. 10) {
auto bölge = merkezdeÜçgenBölge();
tablo[bölge] = sayaç;
}
writeln("Bütün tablo:");
foreach (indeks, değer; tablo) {
writeln(indeks, ": ", değer);
}
/*
* Rastgele renkli başka noktalar da hep tabloda çıkmalılar
*/
foreach (sayaç; 0 .. 10) {
assert(merkezdeÜçgenBölge() in tablo);
}
}
O programı normal olarak derleyip çalıştırırsak çıktısı şöyle oluyor:
Bütün tablo:
[(0,0,mavi),(0,0,yeşil),(0,0,kırmızı)]: 0
[(0,0,yeşil),(0,0,yeşil),(0,0,mavi)]: 1
[(0,0,mavi),(0,0,yeşil),(0,0,kırmızı)]: 2
[(0,0,yeşil),(0,0,kırmızı),(0,0,yeşil)]: 3
[(0,0,yeşil),(0,0,kırmızı),(0,0,kırmızı)]: 4
[(0,0,mavi),(0,0,kırmızı),(0,0,mavi)]: 5
[(0,0,kırmızı),(0,0,yeşil),(0,0,mavi)]: 6
[(0,0,kırmızı),(0,0,mavi),(0,0,kırmızı)]: 7
[(0,0,kırmızı),(0,0,kırmızı),(0,0,kırmızı)]: 8
[(0,0,yeşil),(0,0,yeşil),(0,0,mavi)]: 9
core.exception.AssertError@deneme(16662): Assertion failure
Yani tabloya 10 farklı nesne yerleşmiş; yani yanlış olmuş. Çünkü renklerin önemsiz olmalarını istiyorduk.
Programı '-version=hatasız' seçeneğiyle derlersek, Noktalar'ın toHash işlevi de etkinleşiyor ve bu sefer tabloda tek bir eleman bulunuyor. Çünkü Noktalar'ın toHash işlevi, diğer ikisi gibi rengi gözardı edecek şekilde yazılmış:
$ dmd deneme.d -version=hatasız -w
$ ./deneme
Bütün tablo:
[(0,0,kırmızı),(0,0,kırmızı),(0,0,mavi)]: 9
Özet: bu üç özel işlevin birisi bile tanımlanmışsa, her üçünün de uyumlu olarak tanımlanmaları gerekir.
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]