Golang中的非RESTful元素探讨

Golang中的非RESTful元素探讨 您好,

我十分欣赏“Go”语言所倡导的半确定性系统理念,它似乎拥抱了“REST”或过去“应用式语言”的概念。

其核心思想是,生成结果所需的所有信息都通过输入传递,并且无论何时执行,对于相同的输入,结果都应该是相同的。

然而,“Go”语言中存在一些函数,如果被一个“确定性”函数使用,可能会导致函数的输入无法产生确定性的输出。也就是说,对于相同的输入,函数的结果取决于“Go”语言本身的使用方式和库函数。

我正在尝试对“Go”语言中的这些元素进行分类。

以下是我注意到的一些项目:

全局变量 时间 随机数生成(尽管我不太理解随机数的范围) 来自文件的信息(与全局内存类似) 具有随机顺序的映射 本地环境值,例如MAC地址、操作系统值等

当然,还包括任何在相同输入下不返回相同输出的外部应用程序的结果。

根据我的理解,“Go”语言的概念是更倾向于“RESTful”接口,即输出仅基于输入,尽管自然存在实际限制。我希望对语言中可能导致相同输入下函数产生非确定性输出的函数和能力进行分类,以便理解一个受限或增强的、完全“RESTful”的“Go”语言。


更多关于Golang中的非RESTful元素探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

纯函数,指的是相同的输入总是产生相同的输出,具有引用透明性,以及计算机科学中通常与“纯”相关的所有特性。

更多关于Golang中的非RESTful元素探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go 语言没有表达函数纯度的方式,REST 架构也不假定涉及纯度。

在 REST 中,你今天 GET /product/1,明天再执行一次,价格可能已经改变。所以时间是一个影响因素。

因此,我确实不太理解这个问题。

让我们换一种方式来尝试。

我想确定在“Go”中,哪些因素可能导致基于输入数据产生不同的返回值。我已经识别出了一些。

我正在寻找其他的。一个(较旧的)恰当术语是“应用式”语言,在这种语言中,请求的内容包含了所有必要的信息,连同软件一起,确定性地决定了输出。“Go”有许多这样的函数。我已经识别出了一些不这样表现的函数。我正试图识别出其他的。

当然,“Go”中的许多函数和库都能从输入中产生确定性的输出。我正在大规模地寻找那些不能这样做的函数。主要是那些出乎意料的情况,比如 MAP 为键添加随机性的方式。

Go 无法表达函数的纯粹性

请定义你所说的“纯粹性”是什么意思。

在Go语言中,确实存在一些函数和特性可能导致相同输入下产生非确定性输出,这与RESTful理念中输出仅基于输入的原则相悖。以下是对这些元素的分类及示例代码:

1. 全局变量

全局变量的值可能在函数调用间被修改,导致相同输入产生不同输出。

package main

import "fmt"

var globalCounter int

func nonDeterministicAdd(x int) int {
    globalCounter++
    return x + globalCounter
}

func main() {
    fmt.Println(nonDeterministicAdd(5)) // 第一次调用,输出 6
    fmt.Println(nonDeterministicAdd(5)) // 第二次调用,输出 7
}

2. 时间相关函数

时间函数返回当前时间,每次调用结果不同。

package main

import (
    "fmt"
    "time"
)

func getTimestamp() int64 {
    return time.Now().UnixNano()
}

func main() {
    fmt.Println(getTimestamp()) // 每次调用输出不同
}

3. 随机数生成

math/rand包生成伪随机数,即使种子相同,序列也可能不同。

package main

import (
    "fmt"
    "math/rand"
)

func randomOutput(x int) int {
    return x + rand.Intn(100)
}

func main() {
    fmt.Println(randomOutput(5)) // 多次调用输出不同
}

4. 文件系统操作

读取文件内容可能因文件状态变化而不同。

package main

import (
    "fmt"
    "io/ioutil"
)

func readFileContents(filename string) (string, error) {
    data, err := ioutil.ReadFile(filename)
    return string(data), err
}

func main() {
    content, _ := readFileContents("example.txt")
    fmt.Println(content) // 文件内容变化时输出不同
}

5. 映射的随机迭代顺序

Go语言中映射的迭代顺序是随机的。

package main

import "fmt"

func mapIteration() {
    m := map[string]int{"a": 1, "b": 2, "c": 3}
    for k, v := range m {
        fmt.Printf("%s:%d ", k, v)
    }
    fmt.Println()
}

func main() {
    mapIteration() // 每次运行输出顺序可能不同
}

6. 环境变量和系统信息

获取系统信息(如MAC地址、主机名)可能因环境而异。

package main

import (
    "fmt"
    "os"
)

func getHostname() string {
    hostname, _ := os.Hostname()
    return hostname
}

func main() {
    fmt.Println(getHostname()) // 在不同机器上输出不同
}

7. 并发操作

goroutine的调度顺序不确定,可能导致数据竞争。

package main

import (
    "fmt"
    "sync"
)

var counter int
var wg sync.WaitGroup

func increment() {
    counter++
    wg.Done()
}

func main() {
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go increment()
    }
    wg.Wait()
    fmt.Println(counter) // 多次运行结果可能不同
}

8. 外部服务调用

调用外部API或服务可能返回不同结果。

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func fetchExternalData(url string) (string, error) {
    resp, err := http.Get(url)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)
    return string(body), nil
}

func main() {
    data, _ := fetchExternalData("https://api.example.com/data")
    fmt.Println(data) // 外部数据变化时输出不同
}

这些示例展示了Go语言中可能导致非确定性输出的元素。在构建完全RESTful的系统时,需要避免或严格控制这些元素的使用。

回到顶部