1. 程式人生 > >1. 基礎語法

1. 基礎語法

一. 變數定義

package main

import "fmt"

var (
	// 函式外的變數  並非全域性變數, 而是包內變數
	aa = 3
	ss = "kkk"
)
// 函式外面 不能用:=定義變數

func variableZeroValue() {
	var a int
	var s string // go語言的變數  在定義的時候就會有一個 初始值
	fmt.Printf("%d  %q\n", a, s)
}

func variableInitialValue() {
	var a, b int = 3, 4
	var s string = "abc"
	fmt.Println(a, b, s)
}

func varibleTypeDeduction() {
	var a, b, c, s = 3, 4, true, "def"
	fmt.Println(a, b, c, s)
}

func variableShorter() {
	a, b, c, s := 3, 4, true, "def" // :=   和 var =   一個意思, 只能在第一次定義變數時用
	b = 5
	fmt.Println(a, b, c, s)
}

func main() {
	fmt.Println("Hello world")
	variableZeroValue()
	variableInitialValue()
	varibleTypeDeduction()
	variableShorter()
	fmt.Println(aa, ss)
}


二. 內建變數型別

  • bool, string
  • (u)int, (u)int8, (u)int16, (u)int32, (u)int64, 帶u表示無符號整型
  • uintptr ptr表示指標
  • byte
  • rune 字元型 32位 go中不叫char,優化了char, 避免了很多坑
  • float32, float64
  • complex64, complex128 複數

複數演示

func euler() {
	c := 3 + 4i               //定義複數
	fmt.Println(cmplx.Abs(c)) // 得到5

	fmt.Println(
		cmplx.Exp(1i*math.Pi), // 或者
		cmplx.Pow(math.E, 1i*math.Pi)) // i不會解釋為複數, 需要寫成1i

	//(-1+1.2246467991473515e-16i) (-1+1.2246467991473515e-16i)
	
	// 去掉尾巴  可以使用 fmt.Printf("%0.3d", cmplx.Exp(1i*math.Pi))
}

go只有強制型別轉化

func trangle() {
	var a, b int = 3, 4
	var c int
	c = int(math.Sqrt(float64(a*a + b*b)))  
	fmt.Println(c)
	// 如果寫 var c int = math.Sqrt(a*a, b*b)  會失敗, go只能強制型別轉化, 無法自動轉
}

三. 常量和列舉

常量

  • 例如 const filename = "abc.txt"
  • const 型別可以作為各種型別使用
func consts() {
	const filename = "abc.txt"
	const a, b = 3, 4
	var c int
	c = int(math.Sqrt(a*a + b*b))  //const 型別可以作為各種型別使用,這裡會作為float 
	fmt.Println(filename, c)
}

列舉

  • 普通列舉型別
  • 自增值列舉型別
func enums() {
	//const(
	//	cpp = 0
	//	java = 1
	//	python = 2
	//	golang = 3
	//)
	// 可以簡化為
	const (
		cpp        = iota
		_           //  _表示跳過 1
		python      //2
		golang      //3
		javascript  //4
	)

	fmt.Println(cpp, javascript, python, golang) // 0, 4, 2,3

	// iota更復雜的用法, 可以作為自增值的 種子

	const (
		b        = 1 << (10*iota)
		kb
		mb
		gb
		tb
		pb
	)
	fmt.Println(b, kb, mb, gb, tb, pb) //1 1024 1048576 1073741824 1099511627776 1125899906842624
}

四. 條件語句

if

import (
	"io/ioutil"
	"fmt"
)

func ifexample() {
	const filename = "abc.txt"
	
	// 常規用法
	//contents, err = ioutil.ReadFile(filename)
	//
	//if err != nil {
	//	fmt.Println(err)
	//} else {
	//	fmt.Printf("%s\n", contents)
	//}
	
	
	// if後面可以跟 多個語句的
	// if語句中可以定義變數
	if contents, err := ioutil.ReadFile(filename); err == nil {
		fmt.Println(string(contents))
	} else {
		fmt.Println("cannot print file contents:", err)
	}
	
	// if後的變數只在 if範圍內起作用
}

switch

  • switch 會自動break, 如果不想break, 加fallthrough
func grade(score int) string {
	g := ""
	switch {

	case score < 60 && score >= 0:
		g = "F"
	case score < 80:
		g = "C"
	case score < 90:
		g = "B"
	case score <= 100:
		g = "A"
	default:
		panic(fmt.Sprintf("Wrong score: %d", score)) // panic會終斷程式的執行, 並報錯
	}

	return g
}

func main() {
	fmt.Println(
		grade(0),
		grade(55),
	)
}


五. 迴圈

  • for 的條件裡不加括號
  • for的條件裡可以省略初始條件, 結束條件, 遞增表示式
sum := 0
for i:= 1; i <= 100; i++ {
    sum += 1
}

實際舉例

package main

import (
	"fmt"
	"strconv"
	"os"
	"bufio"
)

func convertToBin(n int) string { //  10進位制轉2進位制
	result := ""
	for ; n > 0; n /= 2 {
		lsb := n%2
		result = strconv.Itoa(lsb) + result
	}

	if result=="" {
		result = "0"
	}
	return result
}


func printFile(filename string) {
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}

	scanner := bufio.NewScanner(file)

	for scanner.Scan() {           // 這裡的for 沒有起始條件和遞增條件 只有結束條件  就相當於while  go語言中沒有while
		fmt.Println(scanner.Text())
	}
}


func forever() {
	for {           //  沒有起始條件, 沒有遞增條件, 也沒有結束條件  相當於死迴圈
		fmt.Println("abc")
	}
}

func main() {
	fmt.Println(
		convertToBin(5),  // 101
		convertToBin(13), // 1101
		convertToBin(0), // 0
	)

	printFile("abc.txt")
}


六. 函式

  • 函式名在前 , 返回值型別在後, 引數也是如此
  • 可以將函式作為引數
  • 可以返回多個值
  • go沒有 預設引數, 可選引數, 過載等複雜操作, 只有可變引數列表...
  • go的匿名函式 就是 直接省略函式名
package main

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
)

func eval(a, b int, op string) (int, error) {//  error返回錯誤
	switch op {
	case "+":
		return a + b, nil   // nil 是沒有被 賦值的變數 函式 類。。。的預設初始值, 類似空指標
	case "-":
		return a - b, nil
	case "*":
		return a * b, nil
	case "/":
		q, _ := div(a, b)  // 有兩個返回值, 但只接收一個返回值
		return q, nil
	default:
		return 0, fmt.Errorf(
			"unsupported operation: %s", op)
	}
}

// 帶餘數的除法
func div(a, b int) (q, r int) {  // 可以返回多值, 並且可以對返回值取名, 編輯器會用改名接收返回值
	return a / b, a % b
}

func apply(op func(int, int) int, a, b int) int {    // 傳入引數op  是函式
	p := reflect.ValueOf(op).Pointer()    // 先獲取指標
	opName := runtime.FuncForPC(p).Name() // 再拿到函式名
	fmt.Printf("Calling function %s with args "+
		"(%d, %d)\n", opName, a, b)

	return op(a, b)
}

func sum(numbers ...int) int {  // ...引數列表, 可以傳任意數量的int
	s := 0
	for i := range numbers {
		s += numbers[i]
	}
	return s
}

func swap(a, b int) (int, int) {
	return b, a
}

func main() {
	fmt.Println("Error handling")
	if result, err := eval(3, 4, "x"); err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Println(result)
	}

	q, r := div(13, 3)  // 接收返回值
	fmt.Printf("13 div 3 is %d mod %d\n", q, r)

	fmt.Println("pow(3, 4) is:", apply(
		func(a int, b int) int {    // 使用go語言的 匿名函式
			return int(math.Pow(
				float64(a), float64(b)))
		}, 3, 4))

	fmt.Println("1+2+...+5 =", sum(1, 2, 3, 4, 5))

	a, b := 3, 4
	a, b = swap(a, b)
	fmt.Println("a, b after swap is:", a, b)
}


七. 指標

  • 指標不能運算
  • go的函式引數都是值傳遞, 想要達到引用傳遞的效果, 可以使用指標
func swap(a, b *int){
	*a, *b = *b, *a
}

func main() {

    a, b := 3, 4
	swap(&a, &b)
}

交換值有更好的方法

func swap(a, b int) (int, int) {
	return b, a
}

func main() {

    a, b := 3, 4
	b, a = swap(a, b)
}