Go与其他语言的不同之处是什么?

前言

因为感冒了而请假休息,于是我决定利用这个机会学习一直以来让我好奇的Go语言,并开始在下面的网站进行学习:https://golang.org/doc/

在学习的过程中,我会写下我认为其他语言中没有的功能。
“其他语言中没有的功能”是指对我来说第一次见到的功能。以下的编程语言应该大致上我都了解,所以这些语言应该没有这个功能。
Pascal, C, Java, Perl, Python, TypeScript
其他语言可能有类似的功能,但还请宽容。

切片的容量 sī de

在这里,我们定义一个长度为6的int数组,它与C语言的数组一样是固定长度的。

arrayedPrimes := [6]int{2, 3, 5, 7, 11, 13}

由于固定长度的数组使用起来不太方便,所以经常使用以下的切片方法。

slicedPrimes := []int{2, 3, 5, 7, 11, 13}

在切片中有长度和容量的概念,长度指的是切片引用的数组大小,容量指的是切片引用的数组直到末尾的大小。

因此,会有以下的行为。

firstSlice := slicedPrimes[0:4] // [2, 3, 5, 7]
len(firstSlice) // -> [2, 3, 5, 7]なので4
cap(firstSlice) // -> [2, 3, 5, 7, 11, 13]なので6

secondSlice := slicedPrimes[2:4] // [5, 7]
len(secondSlice) // -> [5, 7]なので2
cap(secondSlice) // -> [5, 7, 11, 13]なので4

界面的自动实现 de

在Go语言中,没有类的继承。虽然有接口的存在,但程序员并不需要实现接口。
相反,如果某个结构体的方法实现了某个已定义接口的所有方法,那么该结构体将被自动视为实现了该接口。

比如说,给定以下的结构体:

type person struct {
    firstname string
    sirname   string
    age       int
}

假设以下方法已被定义。

func (p person) getSirName() string {
    return p.sirname
}

func (p person) getFirstName() string {
    return p.firstname
}

func (p person) getAge() int {
    return p.age
}

此外,假设定义了以下两个接口。

type japaneseFriend interface {
    getSirName() string
    getAge() int
}

type americanFriend interface {
    getFirstName() string
    getAge() int
}

在这种情况下,结构体”person”并没有编写”implement”等内容,但是它会自动实现”japaneseFriend”和”americanFriend”两者。

下面的代码将person赋值给类型为americanFriend的变量,但是在switch语句中执行类型检查时,会执行japaneseFriend的代码。这说明person既是japaneseFriend又是americanFriend。

// americanFriend型の変数に代入
var friend americanFriend = person{"tanaka", 20}
switch friend.(type) {
case japaneseFriend:
    // japaneseFriend型でもあるので、こちらのコードが実行される
    fmt.Println("Japanese Friend")
case americanFriend:
    fmt.Println("American Friend")
default:
    fmt.Println("none of above")
}

错误接口,不是例外。

由于Go语言中没有异常机制,所以要检测方法执行的错误,需要对方法执行时返回的error值进行检查。

i, err := strconv.Atoi("42")
if err != nil {
    fmt.Printf("couldn't convert number: %v\n", err)
    return
}
fmt.Println("Converted integer:", i)

如果error的值是nil,那就没有问题;如果不是nil,那就表示发生了错误。

协程

要在Go语言中进行异步处理,只需要在方法调用之前写上”go”就可以了。

func someMethod() {
    fmt.Println("hello")
    fmt.Println("goroutine")
}

func main() {
    go someMethod() // 直ちに処理が終了するのでprintはされない
}

在Go语言中,为了在goroutine之间传递值,可以使用channel。channel是一种先进先出(FIFO)的数据结构,可以将其视为消息队列。

通过使用`ch := make(chan string)`,可以生成一个string类型的channel,并将其传递给进行异步处理的方法。

在异步处理的一侧,可以通过`ch <- “hello”`这样的方式将字符串写入channel。

在等待向ch写入的一侧,可以使用`for msg := range ch`这样的方式,阻塞线程的处理直到ch中有消息被写入,并在写入后将消息赋值给msg。

如果在某处调用了`close(ch)`,则会退出循环。

func someMethod(ch chan string) {
    ch <- "hello"
    ch <- "goroutine"
    close(ch)
}

func main() {
    ch := make(chan string)
    go someMethod(ch)
    for msg := range ch {
        fmt.Println(msg)
    }
} 

Go语言之旅练习:网络爬虫问题的我的解决方案

因为有点困难,所以我觉得写下来可能对别人有帮助。

package main

import (
    "fmt"
    "sync"
)

type safeSiteMap struct {
    crawledMap map[string]string
    mutex sync.RWMutex
}

func (siteMap *safeSiteMap) put(url string, body string) {
    siteMap.mutex.Lock()
    siteMap.crawledMap[url] = body
    siteMap.mutex.Unlock()
}

func (siteMap *safeSiteMap) hasCrawled(url string) bool {
    siteMap.mutex.RLock()
    _, ok := siteMap.crawledMap[url]
    siteMap.mutex.RUnlock()
    return ok
}

type Fetcher interface {
    // Fetch returns the body of URL and
    // a slice of URLs found on that page.
    Fetch(url string) (body string, urls []string, err error)
}

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, siteMap safeSiteMap, wg *sync.WaitGroup) {

    defer wg.Done()

    var concreteCrawl func(string, int)
    concreteCrawl = func(url string, depth int) {
        // ensure wg.Done() when method returns
        defer wg.Done()
        if depth <= 0 {
            return
        }
        body, urls, err := fetcher.Fetch(url)
        if err != nil {
            fmt.Println(err)
            return
        }
        siteMap.put(url, body)
        fmt.Printf("found: %s %q\n", url, body)
        for _, u := range urls {
            if siteMap.hasCrawled(u) {
                continue
            }
            wg.Add(1)
            go concreteCrawl(u, depth-1)
        }
    }
    wg.Add(1)
    go concreteCrawl(url, depth)
    return
}

func main() {
    siteMap := safeSiteMap{crawledMap: make(map[string]string)}
    var wg sync.WaitGroup
    wg.Add(1)
    go Crawl("https://golang.org/", 4, fetcher, siteMap, &wg)
    wg.Wait()
    for url, body := range siteMap.crawledMap {
        fmt.Println("  " + url + ": " + body)
    }
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
    body string
    urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
    if res, ok := f[url]; ok {
        return res.body, res.urls, nil
    }
    return "", nil, fmt.Errorf("not found: %s", url)
}


// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}

以下是对”感触”的中文本地化改写:

触动心灵

虽然它具备了新颖的功能,但仍然能提高执行速度,可以感受到一些类似C语言的味道。
经过大约5小时的学习,我能感受到它的潜力,但不清楚其生态系统的状况,所以无法确定在实际开发中会有多少便利。
然而,我认为与C++相比,它似乎不容易出现故障,所以如果未来有各种项目采用Go语言,那将是幸福的事情。加油伟大的人,加油嵌入式开发等其他领域。

广告
将在 10 秒后关闭
bannerAds