Aşırı dönüş türü işlev?
Neden daha mainstream statik olarak yazılan diller fonksiyon, metot dönüş tipi aşırı yükleme desteği yok? Bunu herhangi düşünemiyorum. Az parametre Türüne göre aşırı destekleyen daha yararlı ya da makul görünüyor. Nasıl bu kadar az popüler oluyor?
CEVAP
Diğerleri, dönüş türü tarafından aşırı söylediğinin aksinemümkünbazı modern diller tarafından yapılır. Her zamanki itiraz kodu gibi
int func();
string func();
int main() { func(); }
func()
* deniyor ki söyleyemezsin. Bu birkaç yolla çözülebilir:
- Böyle bir durumda denir belirlemek için tahmin edilebilir bir yöntem var.
- Böyle bir durum olduğunda, bir derleme zamanı hatası. Ancak, programcı belirsizliği ortadan kaldırmak için izin veren bir sözdizimi vardır, örneğin
int main() { (string)func(); }
. - Yan etkileri yoktur. Yan etkileri yok ve hiç bir işlevin dönüş değeri kullanın, sonra derleyici böyle bir işlevi çağırmadan önleyebilirsiniz.
Ben düzenli olarak (ab)tekrar dönüş türü: dil ikiPerlveHaskell. Bana yaptıklarını tarif edeyim.
Perlarasında temel bir fark vardırskalervelistebağlam (ve diğerleri, ama iki tane var sayalım). Her yerleşik perl'de fonksiyon farklı şeyler bağlı olarak yapabilirbağlamhangi denir. Örneğin, join
operatör scalar
operatör bağlam, yani karşılaştırmak: skaler güçleri ise liste bağlam şey katılmış olmak () zorlar
print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.
Perl her operatör skaler bağlamda bir şey ve liste bağlamda bir şey yok, ve resimli olarak farklı olabilirler. (Bu sadece localtime
gibi rasgele operatörler için değil. Eğer liste bağlamda bir dizi @a
kullanırsanız, skaler bağlamda, öğe sayısını döndürür süre diziyi verir. Örneğin print @a
print 0 @a
boyutu baskı sırasında öğeleri yazdırır.) Ayrıca, her operatörzorlaörneğin içerik bir ek
skaler bağlamda zorlar. man perlfunc
Her Giriş Bu belge. Örneğin, burada glob EXPR
giriş parçası
Bağlam, bir (muhtemelen listesini verir boş) dosya adı uzantılarına listesi standart olarak
EXPR
değeri/bin/csh
shell Unıx yapardı. İçinde üzerinden skaler bağlamda tulumu dolaşır bu dosya adı uzantılarına, dönen liste kaldığında undef.
Şimdi, skaler ve liste bağlamı arasındaki ilişki nedir? İyi, man perlfunc
diyor
Unutmayın aşağıdaki önemli kural: Eğer ilgili kural yok listedeki bir ifade davranış skaler kendi davranış bağlam bağlam, ya da tam tersi. Yapabilir tamamen farklı iki şey. Her operatör ve fonksiyon kesinleşir en olurdu değeri sıralama uygun skaler dönmek bağlam. Bazı operatörler dönüş ki listenin uzunluğu liste içerik. iade edilmiş Bazı operatörler ilk değeri döndürür liste. Bazı operatörler dönüş listedeki son değer. Bazı operatörler başarılı bir geri sayım işlemleri. Genel olarak, ne yapıyorlar tutarlılık istemiyorsan.
tek bir işlevi olan basit bir mesele değil, ve sonra basit bir dönüşüm sonunda. Aslında, bu nedenle localtime
örnek seçtim.
Sadece bu davranış-ins inşa değil. Herhangi bir kullanıcı böyle bir fonksiyon listesi, skaler ve boşluk içeriği arasında ayırt etmek için izin verir wantarray
kullanarak tanımlayabilirsiniz. Bu yüzden, örneğin, eğer boşluk bağlamda sizi çağırıyorlar eğer bir şey yapmaya karar verebilirsiniz.
Şimdi, bu değil şikayet edebilirsinizdoğrudönüş aşırı yüklenme sadece deniyor bağlamında söyledim ve sonra da bu bilgilere dayanarak hareket eden bir fonksiyon, çünkü değer. Ancak, bu (ve Perl her zamanki kelimenin tam anlamıyla aşırı yükleme izin vermez, ama bir işlev bağımsız değişkenleri incelemek nasıl benzer) açıkça eşdeğerdir. Ayrıca, güzelce belirsiz durum bu yanıtın başında da belirtildiği giderir. Perl aramak için hangi bilmiyor şikayetçi değildir, sadece çağırır. Gerisi ona kalmış. her zaman mümkün olan fonksiyonu içinde ne olduğunu anlamaya
sub func {
if( not defined wantarray ) {
print "void\n";
} elsif( wantarray ) {
print "list\n";
} else {
print "scalar\n";
}
}
func(); # prints "void"
() = func(); # prints "list"
0 func(); # prints "scalar"
(Not: bazen işlevi yani ne zaman Perl operatör diyebilirim. Bu tartışma için çok önemli değildir.)
Haskelldiğer yaklaşım, yani yan etkisi olmayan alır. Aynı zamanda güçlü bir tip sistemine sahiptir, ve bu yüzden aşağıdaki gibi bir kod yazabilirsiniz:
main = do n <- readLn
print (sqrt n) -- note that this is aligned below the n, if you care to run this
Bu kod standart girdiden bir kayan nokta sayısı okur ve kare kökü yazdırır. Ama bu konuda şaşırtıcı bir şey var mı? İyi, readLn
tipi readLn :: Read a => IO a
. Bunun anlamı, herhangi bir türü için Read
(resmi olarak, Read
yazın sınıfın bir örneği her türü), readLn
olabilir ne okuyabilir. Nasıl Haskell kayan noktalı bir sayı görmek istedim biliyor muydunuz? İyi, sqrt
türü aslında sqrt
sadece kayan nokta sayıları girdi olarak kabul edebilir anlamına gelir sqrt :: Floating a => a -> a
, ve ne istediğimi çok Haskell anlaşılmaktadır.
Ne istediğimi anlaması Haskell o zaman ne yapacağız? Birkaç olasılık var. Eğer dönüş değeri hiç kullanmıyorum bile, Haskell, sadece ilk etapta bir işlev çağrısı olmayacak. Ancak, eğer benyapındönüş değeri kullanın, sonra Haskell türü gerçekleştirip olabilir mi şikayet edecektir:
main = do n <- readLn
print n
-- this program results in a compile-time error "Unresolved top-level overloading"
İstiyorum türünü belirterek belirsizlik çözebileceğime:
main = do n <- readLn
print (n::Int)
-- this compiles (and does what I want)
Dönüş değeri aşırı yükleme mümkün ve yapılır, soru cevaplar parçası olan bütün bu tartışma ne demek zaten.
Sorunuzun diğer kısmı daha fazla dil yapma nedeni budur. Diğerleri de buna cevap veririm. Ancak, bir kaç yorum: akıl karışıklığı için gerçekten büyük bir fırsat burada aşırı daha büyük olasılıkla bağımsız değişken Türüne göre ilkedir. Ayrıca tek tek diller: gerekçeleri bakabilirsiniz
Ada: "en basit aşırı çözümleme kuralı her şeyi mümkün olduğunca geniş bir bağlamdan tüm bilgi - aşırı başvuru gidermek için kullanmak gibi görünebilir. Bu kural basit olabilir, ama yararlı değildir. İnsan okuyucu keyfi metin büyük parçaları taramak için, ve keyfi karmaşık çıkarımlar (yukarıda (g) gibi) yapmak gerekir. İyi bir kural, açık bir insan bir okur ya da derleyici gerçekleştirmelisiniz görev yapan biri olduğuna inanıyoruz ve bu görevi mümkün olduğunca insan okuyucu için doğal olarak yapar."
(Bjarne Stroustrup ... ... alt bölüm 7.4.1"") C Programlama Dili: "Dönüş türleri aşırı çözümleme dikkate alınmaz. C Sebebi tek operatör veya bir işlev çağrısı kapsamında bağımsız çözünürlük tutmaktır. Düşünün:
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl = sqrt(da); // call sqrt(double)
double d = sqrt(da); // call sqrt(double)
fl = sqrt(fla); // call sqrt(float)
d = sqrt(fla); // call sqrt(float)
}
Eğer dönüş türü hesaba katıldığında, artık yalıtım sqrt()
bir ara bakıp işlevi çağrıldı belirlemek mümkün olacaktır." (Haskell yok olduğunu, karşılaştırma için, unutmayınörtülüdönüşüm.)
Java (Java Language Specification 9.4.1): "miras yöntemlerden Biri olmalı başka bir yöntemi miras için değiştirilebilir tip iadesi gerekir; aksi halde, bir derleme zamanı hatası oluşur." (Evet, bu bir gerekçe vermez biliyorum. Gerekçe Gosling tarafından verilir eminim"". Java Programlama Dili Belki birisi bir kopyası var mı? Eminim bunu "prensip en az" özü.) sürpriz. Ancak, Java hakkında ilginç bir bilgi: JVMsağlardönüş tarafından aşırı değer! Bu, örneğin, Scala kullanılır directly through Java iç uğraşırken de erişilebilir.
PS. Son bir not olarak, aslında C dönüş değeri tarafından aşırı olası bir hile ile. Tanık:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Dönüş türü işlev imzası bir parçası mı...
Dönüş türü ile Java yöntemi return ifa...
Dönüşü olmayan işlev temsilci türü...
Erken verimli bir işlev dönüş...
nasıl aşırı bir işlev için bir işaretç...