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语言,那将是幸福的事情。加油伟大的人,加油嵌入式开发等其他领域。