博客 / 詳情

返回

跟老衞學倉頡編程語言開發:函數

函數在倉頡語言中是普遍存在的。通過之前的章節已經可以瞭解到倉頡函數的基本形式:main()函數是很多程序的入口點,func關鍵字用來聲明函數。

本節將初步探討函數,內容包括定義函數、函數參數、函數返回值等。在第11章還會對函數進行深入的講解。

本節示例可以在“function_demo”應用下找到。

定義函數

倉頡使用關鍵字func來表示函數定義的開始,func之後依次是函數名、參數列表、可選的函數返回值類型、函數體。其中,函數名可以是任意的合法標識符,參數列表定義在一對圓括號內(多個參數間使用逗號分隔),參數列表和函數返回值類型(如果存在)之間使用冒號分隔,函數體定義在一對花括號內。

以下是一個自定義函數的示例:

// main函數是程序入口
main() {
    // 執行函數
    println_hello();
}

// 自定義函數
func println_hello() {
    // 打印Hello World!
    println("Hello World!");
}

上述示例脱胎於“Hello World”應用,只是將打印字符串的邏輯封裝到了自定義函數println_hello中。上述例子執行之後輸出內容如下:

Hello World!

定義函數需要注意以下幾點:

  • 函數名和變量名使用蛇形命名法(snake case),例如println_hello();
  • 函數的位置可以隨便放;
  • 如果函數定義了參數,則參數都需要標註類型。

函數參數

倉頡是強類型語言,因此如果函數定義了參數,則參數都需要標註類型,例如:

// main函數是程序入口
func main() {
    // 執行函數傳遞參數
    let text = 999;
    println_text(text);
}

// 如果函數定義了參數,則參數都需要標註類型
func println_text(text: Int64) {
    println("text: ${text}");
}

上述例子中,println_text函數有一個參數類型是Int64。上述例子執行之後輸出內容如下:

text: 999

一個函數可以擁有0個或多個參數,這些參數均定義在函數的參數列表中。根據函數調用時是否需要給定參數名,可以將參數列表中的參數分為兩類:非命名參數和命名參數。

非命名參數的定義方式是p: T,其中p表示參數名,T表示參數p的類型,參數名和其類型間使用冒號連接。例如,以下add函數的兩個參數a和b均為非命名參數。

func add(a: Int64, b: Int64): Int64 {
    return a + b;
}

命名參數的定義方式是p!: T,與非命名參數的不同是在參數名p之後多了一個“!”。可以將上例中add函數的兩個非命名參數修改為命名參數,如下所示:

func add(a!: Int64, b!: Int64): Int64 {
    return a + b
}

命名參數還可以設置默認值,通過“p!: T = e”方式將參數p的默認值設置為表達式e的值。例如,可以將上述add函數的兩個參數的默認值都設置為1:

func add(a!: Int64 = 1, b!: Int64 = 1): Int64 {
    return a + b
}

:只能為命名參數設置默認值,不能為非命名參數設置默認值。

參數列表中可以同時定義非命名參數和命名參數,但是需要注意的是,非命名參數只能定義在命名參數之前,也就意味着命名參數之後不能再出現非命名參數。例如,下例中add函數的參數列表定義是不合法的:

// 錯誤!命名參數之後不能再出現非命名參數
func add(a!: Int64, b: Int64): Int64 {
    return a + b
}

上述函數會報如下錯誤:

error: unnamed parameters must come before named parameters
  ==> main.cj:39:21:
   |
39 | func add(a!: Int64, b: Int64): Int64 {
   |          ~~~~~~~~~  ^^^^^^^^ unexpected unnamed parameter here
   |          |
   |          because it must come before this named parameter
   |

1 error generated, 1 error printed.

函數參數均為不可變變量,在函數定義內不能對其賦值。

func add(a: Int64, b: Int64): Int64 {
    a = a + b // 錯誤!
    return a
}

函數參數作用域從定義處起至函數體結束:

func add(a: Int64, b: Int64): Int64 {
    var a_ = a // 正確
    var b = b  // 錯誤!
    return a
}

函數返回

函數返回值類型是函數被調用後得到的值的類型。函數定義時,返回值類型是可選的:可以顯式地定義返回值類型(返回值類型定義在參數列表和函數體之間),也可以不定義返回值類型,交由編譯器推導確定。

當顯式地定義了函數返回值類型時,就要求函數體的類型、函數體中所有return e表達式中e的類型是返回值類型的子類型,否則則會因為類型不匹配而報錯。

以下是一個函數返回的例子:

// main函數是程序入口
main() {
    // 獲取函數的返回值
    let a: Int64 = 1;
    let b: Int64 = 1;
    let add_result = add(a, b);
    println("add result: {add_result}");
}

// 定義帶返回的函數
func add(a: Int64, b: Int64): Int64 {
    return a + b;
}

上述例子中,add函數有兩個參數類型都是Int64,該函數會返回Int64類型的值。在函數定義時如果未顯式定義返回值類型,編譯器將根據函數體的類型以及函數體中所有的return表達式來共同推導出函數的返回值類型。例如,上述例子中add函數的返回值類型可以被省略,但編譯器仍然可以根據return a + b推導出add函數的返回值類型是Int64。

返回的值用關鍵字return標識。如果返回的值,是函數的最後一行,那麼也可以不需要關鍵字return,示例如下:

// 定義帶返回的函數
func add(a: Int64, b: Int64): Int64 {
    // 等同於 
    // return a + b;
    a + b
}

上述例子執行之後輸出內容如下:

add result: 2

:函數的返回值類型並不是任何情況下都可以被推導出來的,如果返回值類型推導失敗,編譯器會報錯。指定返回類型為Unit時,編譯器會在函數體中所有可能返回的地方自動插入表達式return (),使得函數的返回類型總是為Unit。

參考引用

  • 免費開源書《跟老衞學倉頡編程語言開發》
  • 免費開源書《跟老衞學HarmonyOS開發》
  • HarmonyOS NEXT+AI大模型打造智能助手APP(倉頡版)(視頻)
  • 倉頡編程從入門到實踐(北京大學出版社)

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.