簡體   English   中英

為什么方法簽名中不包含方法的返回類型?

[英]Why is the return type of method not included in the method-signature?

為什么簽名中不包含方法的返回類型?

一個例子

public void method1(String arg){...}

public String method1(String arg){...}

它會導致錯誤。

這樣做是因為編譯器無法計算出所有上下文中的重載。

例如,如果您調用

String x = method1("aaa");

編譯器知道您正在尋找第二個重載。 但是,如果您調用

method1("aaa");

像這樣,編譯器不知道你想調用這兩個方法中的哪一個,因為調用一個返回String的方法並丟棄結果是可以的。 為了避免這樣的歧義,Java 禁止僅在返回類型上不同的重載。

由於您的問題沒有解決標題中的任何特定編程語言(我知道它在標簽中)我將分享我最近使用Swift 的經驗。 Swift函數/方法簽名實際上包括返回類型。 因此,僅當您在未明確指定返回類型的情況下調用此函數/方法時,編譯器才會拋出錯誤,例如:

func some() -> Bool {
    return true;
}

func some() -> Int {
    return 1;
}

let valBool: Bool = some()
let valInt: Int = some()

// this doesn't work: Ambiguous use of 'some'
some()

除此之外,Swift 甚至讓它變得更有趣。 它允許您擁有 2 個具有相同參數的函數/方法,並且僅當參數名稱不同時才返回類型,例如:

func some(#foo: Bool) -> Bool {
    return foo;
}

func some(#bar: Bool) -> Bool {
    return bar;
}

some(foo: true)
some(bar: false)

因此,它為您提供了方法簽名中的語義區分

更新。 由於 Swift 2.0 外部參數名稱已更改,現在您必須提供兩次外部和本地名稱,即使它們相同

func some(foo foo: Bool) -> Bool {
    return foo;
}

func some(bar bar: Bool) -> Bool {
    return bar;
}

some(foo: true)
some(bar: false)

您不能僅根據其返回類型重載方法。 這簡直是​​非法的。 讓我們暫時假設使用返回類型重載方法是合法的,並且您定義了兩個method1方法。 現在我們要調用返回String object那個:

String string = method1(sth);

JVM 理論上能夠識別您打算調用哪個方法,但是這樣的調用呢:

method1(sth);

正如您所看到的,這兩種方法都可以被調用,而且這樣的操作是明確的。 JVM 不知道它應該調用哪個方法。 這就是禁止這種超載的原因。

因為在這樣的情況下無法確定應該調用哪個重載方法:

public static void main(String... args) {
    method1("aaa");
}

在設計諸如重載解析之類的東西時,有幾點需要考慮。

忽略返回類型重載的原因:

  1. 簡化忽略函數返回值(就像人們經常對錯誤代碼所做的那樣)。
  2. 使人類讀者更容易消化程序。 特別是,這就是在 Python 中它們根本沒有函數重載的原因。 (口味問題)
  3. C 遺產。 當語言來自 C 系列並且設計師不認為某事是什么大問題時,它會像往常一樣......

在返回類型上添加重載的原因:

  1. 使忽略返回值變得困難。 這可能很方便並節省了一些打字的時間,但總有一天會咬你。
  2. 表現力(當然與易於消化相反:))。 你有沒有想過寫像int x = json.get("int_value"); float y = json.get("float_value"); int x = json.get("int_value"); float y = json.get("float_value"); ? 在某些語言(如 C++)中,仍然可以使用代理和強制轉換運算符來實現,但返回類型的重載會容易得多。
  3. 表現力。 每次將 retun 值作為對函數的引用傳遞只是為了重用其資源時,這可能是返回類型的重載(帶有類似隱藏參數)。 考慮string s; getline(cin, s); string s; getline(cin, s); vs string s = getline(cin); . 這就是表現力與引用透明性相結合的地方,最終,易於代碼消化。

現在回到你的問題“為什么?”。 既然您問的是 Java,答案顯然是因為 James 重視省略返回類型重載的原因而不是將它們包含在語言中的原因。

我自己曾經有過同樣的問題,雖然我可以看到編譯器如何在您不將返回值分配給適當類型的變量時不知道要調用哪個函數,但為什么在功能層面? 為什么不在調用函數的時候? 基本上,一旦您承諾讓簽名僅因返回值而不同,您就可以確保以這種方式使用它們,然后編譯器才會抱怨。 當然,使用嚴格的一次性編譯器可能需要一些額外的工作,但我認為它可以飛。

您可以將函數作為過程調用: method1("arg"); 其中 method1 是列表中的第二個方法( String method1(String arg){} )。 然后編譯器將無法將它與第一個( void method1(String arg){} )區分開來。

編譯器負責方法綁定。 當它遇到 methodName() 時,它必須綁定到某個方法定義,此時它可能不知道方法的返回類型。 所以方法返回類型不包含在方法簽名中。 編譯器根據方法簽名綁定方法。

當編譯器遇到方法調用時。 它將方法調用靜態綁定到定義的方法之一。 讓我們看看如果返回類型包含在方法簽名中會發生什么

class Example{
    public void method1(String arg){ return arg} 
    public String method1(String arg){}
    public static void main(String[] args){
        Example e = new Example();
        e.method1("abc");   
     }  
} 

e.method1("abc")如果方法簽名中包含返回類型,編譯器將不知道要綁定到哪個方法。

方法重載是根據參數的數量和類型而不是返回類型來檢查的。 這就是您收到錯誤的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM