Обработване на грешки

21.10.2014

Въпрос за мъфин #1

Могат ли да се наследяват типове?

Въпрос за мъфин #2

По какво се различава синтаксисът за викане на метод върху обект и върху указател към обект?

Въпрос за мъфин #3

За какво можем да използваме таговете на поле в struct?

Въпрос за мъфин #4

Какво е метод? Могат ли да се добавят методи извън пакета, в който е дефиниран типът?

Въпрос за мъфин #5

Как да накараме наш тип да имплементира интерфейс?

Бонус въпрос за ДВА мъфина!

Дайте дефиниция на полиморфизъм, с три думи без да използвате чуждици!

...

Имало едно време чисто С

Пример в C

#include <stdio.h>
#include <errno.h>
#include <string.h>

extern int errno;

int main ()
{
    FILE* pf = fopen("unexist.txt", "rb");
    if (pf == NULL)
    {
        fprintf(stderr, "Value of errno: %d\n", errno);
        perror("Error printed by perror");
        fprintf(stderr, "Error opening file: %s\n", strerror(errno));
    }
    else
    {
        fclose(pf);
    }
    return 0;
}

Имало едно време един език Go

Има грубо-казано 2 начина

Връщане на грешка

type error interface {
    Error() string
}
type PathError struct {
    Op string    // "open", "unlink", etc.
    Path string  // Файлът с грешката
    Err error    // Грешката, върната от system call-a
}

func (e *PathError) Error() string {
    return e.Op + " " + e.Path + ": " + e.Err.Error()
}

Стандартна употреба

func CreateFile(filename string) {
    file, err = os.Create(filename)
    if err == nil {
        return
    }
    if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOSPC {
        deleteTempFiles()
        CreateFile(filename)
    }
}

defer

Пример:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }

    dst, err := os.Create(dstName)
    if err != nil {
        return
    }

    written, err = io.Copy(dst, src)
    dst.Close()
    src.Close()
    return
}

По-красивият, правилен и работещ начин е това:

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()

    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()

    return io.Copy(dst, src)
}

Доуточнения

Три прости правила за defer (1)

func a() {
    i := 0
    defer fmt.Println(i)
    i++
    return
}

Три прости правила за defer (2)

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

Три прости правила за defer (3)

func c() (i int) {
    defer func() { i++ }()
    return 1
}

Примери

package main

import (
	"fmt"
)

func deferExample() {
    for i := 0; i < 5; i++ {
        defer func(i int) {
            fmt.Printf(" %v", i)
        }(i)
    }
}

func main() {
	deferExample()
}

-

package main

import (
	"fmt"
)

func deferExample() {
    for i := 0; i < 5; i++ {
        defer func() {
            fmt.Printf(" %v", i)
        }()
    }
}

func main() {
	deferExample()
}

Паника!

Уточнения

Избягвайте ненужното изпадане в паника

recover

Example (1)

func g(i int) {
    if i > 3 {
        fmt.Println("Panicking!")
        panic(fmt.Sprintf("%v", i))
    }
    defer fmt.Println("Defer in g", i)
    fmt.Println("Printing in g", i)
    g(i + 1)
}

Example (2)

func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
        }
    }()
    fmt.Println("Calling g.")
    g(0)
    fmt.Println("Returned normally from g.")
}

Example (3)

package main

import "fmt"

func main() {
    f()
    fmt.Println("Returned normally from f.")
}

func f() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
		}
	}()
	fmt.Println("Calling g.")
	g(0)
	fmt.Println("Returned normally from g.")
}

func g(i int) {
	if i > 3 {
		fmt.Println("Panicking!")
		panic(fmt.Sprintf("%v", i))
	}
	defer fmt.Println("Defer in g", i)
	fmt.Println("Printing in g", i)
	g(i + 1)
}

Въпроси?