Golang中如何解决Error: a() (no value) used as value的错误

Golang中如何解决Error: a() (no value) used as value的错误

func a() {
  return
}
func b() {
  return a()
}

如果 a() 不返回值,而 b() 返回 a(),那么 b() 也必须不返回值,对吗?图片

20 回复

我经常遇到这种情况 😊

更多关于Golang中如何解决Error: a() (no value) used as value的错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


有什么原因让你不使用 defer 吗?

func main() {
    fmt.Println("hello world")
}

实际上,我也不知道是什么在困扰我……可能是我多虑了 :sob: 我经常为小事想太多 :sob:

既然无论如何你都会关闭它,为什么不使用 defer 呢?

我根据条件关闭连接。例如,仅当发生错误时才关闭连接。

我在这里使用了一个HTTP连接。HTTP协议是无状态的,这意味着主函数无法持有任何会话变量(除非我使用全局变量)。

实际上,这并非完整的代码。我正在使用 WebSocket,因此我在一个循环中监听事件,并在函数末尾的循环结束后关闭连接。

嗯……如果你已经觉得第一个版本更清晰,那具体问题是什么呢?😊 编辑:为了澄清:在更清晰的版本中,你究竟不喜欢什么,以至于想要使用不那么清晰的代码?

说实话……我认为Go并不是唯一禁止这种语法的语言;我很确定C语言也是如此。

我理解这样一来,每条类似的语句会少写一行代码,但是……在我看来,这是一种容易引起混淆的语法。

错误信息表明您试图返回某些内容,但实际上没有可供返回的内容。

您想要实现什么功能?

在您的情况下,应该这样写:

func a() {
    return
}

func b() {
    a()
    return
}

更准确地说……在这个例子中,两个 return 都是无用的。

我实际在做的是创建一个类似 map[事件名称]事件处理函数 的映射,在一个无限循环中,每当事件被触发时,就会查找映射并运行对应的函数。

func main() {
    fmt.Println("hello world")
}

我是Go语言的新手,但我一直认为应该“返回nil”或者不返回任何内容。 此外,在打开套接字之后,我会使用defer。一旦会话不再需要——就关闭它。

如果你需要在多个地方使用它,那么为什么不在main()中打开连接并使用defer呢?

我的理解有误吗?

是的,这正是我在第二次回复中提到的……我不必浪费时间深究被调用函数的返回值。但 Go 语言强迫我使用更简洁的版本 :roll_eyes:

实际上,C语言是允许这样做的(如果我说错了请见谅,我对C语言还是个新手)。

#include<stdio.h>

void a() {
  printf("in a\n");return;
}

void b() {
  printf("in b\n");
  return a();
}

int main() {
  b();
  return 0;
}

我试了一下,它按预期工作了。

如果没有发生错误,你会让连接保持打开状态,处于悬空状态吗?

要么你的函数最终负责关闭它,要么它需要一种方式来返回连接,以便用户在必要时可以关闭它。

在这种情况下,还应该返回一个错误,以便用户知道他们以后是否需要手动关闭它……

但有时关闭,有时不关闭,这听起来真的会给未来的你带来麻烦……

以下是我的代码简要概述

func joinGame(w http.ResponseWriter, r *http.Request) {
  s := newSocket(w, r)
  s.once("join-player-info", func(data []byte) {
    var pInfo struct {
      Name string `json:"playerName"`
      Side string `json:"side"`
    }
    err = json.Unmarshal(data, &pInfo)
    // 我的问题
    if err != nil {
      s.close()
      return
    }
  })

  // 这是一个无限循环
  s.listen()
  // 在无限循环后关闭socket连接
  s.close()
}

你说的没错,但如果我们能写成 return a() 那样,似乎可以减少代码行数。

我在我的HTTP处理程序中多次遇到这种情况。

s.close() 不返回任何值)

err = json.Unmarshal(data, &pInfo)
if err != nil {
	s.close()
	return
}

相反,我想写成这样:

err = json.Unmarshal(data, &pInfo)
if err != nil {
	return s.close()
}

是的,这可能是个有点傻的问题,但“无值”本身又算什么呢?既然调用栈后面不会用到它,为什么我不能返回一个“无值”呢?

当然,使用第一种写法确实更清晰,因为它明确表明了函数的返回值,我就不需要再深入探究返回值是什么了。

( s.close() 不返回值 )

err = json.Unmarshal(data, &pInfo)
if err != nil {
	s.close()
	return
}

而我想要写成

err = json.Unmarshal(data, &pInfo)
if err != nil {
	return s.close()
}

编写优秀的代码不在于节省一行。优秀的代码应该清晰易读。

你的第一个代码示例非常清晰。我们可以看到这个函数:

  • 调用了 s.close()
  • 没有返回值

你的第二个代码示例读起来可能会令人困惑,因为它似乎在说: “返回 s.close() 的结果”

但实际上没有结果可以返回。读者必须去查找 s.close() 的定义,或者滚动到当前函数的开头,才能发现 return s.close() 实际上什么也不返回。

所以第一个版本要清晰和易读得多,不是吗? 再次强调,在努力编写清晰代码时,节省一行显然不是一个目标。

是的,你的理解完全正确。在Go语言中,函数签名必须严格匹配。如果函数 a() 没有返回值,那么试图在 b()return 语句中返回 a() 的结果会导致编译错误:“a() (no value) used as value”。

这是因为 return a() 试图使用一个不产生任何值的函数调用作为返回值,这在Go的类型系统中是不允许的。

解决方案:

  1. 如果 b() 也不需要返回值,那么应该将 b() 的签名改为无返回值,并直接调用 a(),不使用 return
  2. 如果 b() 需要返回值,那么 a() 也必须返回相应类型和数量的值。

以下是两种情况的示例代码:

情况1:b() 也不需要返回值

func a() {
    // 做一些操作,不返回值
    return
}

func b() {
    // 直接调用 a(),不使用 return
    a()
}

情况2:b() 需要返回值,修改 a() 以返回值

func a() int {
    // 做一些操作,并返回一个整数值
    return 42
}

func b() int {
    // 现在可以正确返回 a() 的结果
    return a()
}

或者,如果 a() 需要返回多个值:

func a() (int, string) {
    return 42, "answer"
}

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

关键点是:在 return 语句中使用的函数调用必须产生与当前函数返回值类型和数量完全匹配的值。如果 a() 没有返回值,那么它就不能用在 b()return 语句中,除非 b() 本身也没有返回值声明。

回到顶部