Golang中参数传递的相关问题探讨

Golang中参数传递的相关问题探讨 再次问候 Golang Bridge!今天过得怎么样?希望一切顺利!

我已经一年多没有接触 Go 语言了,这让我失去了用 Go 思维思考的能力。所以,是的。我有几个不同的问题,针对几个不同的例子。希望能有人向我解释为什么可以或为什么不可以。

这可能会成为论坛里一系列愚蠢的问题。 如果有什么地方表述不清,请见谅,我已经尽力避免混乱。

1. 第一个问题 我想从用户输入中读取值。例如,下面这段代码:

读取输入并在读取函数中传递参数。

func readInput() {
	var lines, columns int
	fmt.Println("Lines:")
	fmt.Scan(&lines)
	fmt.Println("Columns:")
	fmt.Scan(&columns)

	mulTab(lines, columns)    // 在这里传递值
}

func mulTab(lin, col int) int {
	var result int

	for lines = 1; lines <= lin; lines++ {
		for columns = 1; columns <= col; columns++ {
			result = columns * lines
			fmt.Println(columns, "x", lines, "=", result)
		}
	}
	return result
}

我想将输入的值传递给 mulTab 函数。在 readInput 函数中调用 mulTab 函数,这是好的做法吗?是否有其他(更好的)方法来实现这个?

2. 第二个问题 在第二个例子中,我想列出目录中的文件。是的,我知道有更好的方法,比如 ioutil.Readdir。但这不是我的问题所在。

  • 像我这样在 main() 中传递整个函数作为参数是否正确?
  • func readDir() 中,我注释掉了 defer f.Close(),因为如果我在这里关闭,在 func listDir() 中会出现 ‘use of closed file’ 错误。我可以在一个函数中进行 os.Open() 操作,而在另一个函数中关闭它吗?
func readDir() *os.File {
	f, err := os.Open(".")
	if err != nil {
		log.Fatal("Cannot read directory")
	}
	// defer f.Close()
	return f
}

func listDir(s *os.File) []string {
	list, err := s.Readdirnames(0)
	if err != nil {
		log.Fatalln(err)
	}
	for _, name := range list {
		fmt.Println(name)
	}
	defer s.Close()
	return list
}

func main() {
	listDir(readDir())
}

3. 第三个问题

我想创建一个文件。然后我希望能够在另一个函数中向这个文件写入内容。如何将文件名传递给另一个函数?假设文件名是未知的(文件名可以从输入中获取)。os.Create 返回 os.File,而 os.OpenFile() 需要我返回 string

func create() os.File {
	f, err := os.Create(filename_from_input)
	if err != nil {
		log.Fatal("Can't create file:", err)
	}
	defer f.Close()
	return *f
}

我无法将文件名从 create() 传递给 write(),因为 ioutil.WriteFile 只接受 string 类型的文件名,而 create() 返回的是 os.File

func write() {
	os.OpenFile()
	err := ioutil.WriteFile("file.txt", data, 0644) {

	}
}

或者也许我根本不应该把代码拆分成小函数,而应该在一个函数中完成这些操作?我正在寻找正确的方法,这就是我使用这些例子的原因。


更多关于Golang中参数传递的相关问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

第二点和第三点也与同一个问题相关。编写一个返回指针的函数,在接收后可以延迟关闭。

package main

import (
    "log"
    "os"
)

func create() *os.File {
    f, err := os.Create("filename")
    if err != nil {
        log.Fatal("Can't create file:", err)
    }
    return f
}

func main() {
    file := create()
    defer file.Close()

    //对文件进行一些操作
}

更多关于Golang中参数传递的相关问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我想将输入的值传递给 mulTab 函数。在 readInput 函数中调用 mulTab 函数,这是一种好的做法吗?

如果你想调用一个函数,就必须调用它。如果你想使用从标准输入以外的来源收集的参数来调用 mulTab,你应该修改 readInput 函数,使其返回 linescolumns,然后用它们来调用 mulTab

实际上,你在第二个代码片段中就是这么做的:你调用了 readDir 并使用其结果作为 listDir 的参数。

好的,我将我的回答限制在与这两点相关的内容上。关于你第二个问题中的第二点和第三个问题,请另开新帖讨论。

一个函数应该只执行单一任务。与lutzhorn的评论类似,请参考我下面的方法。我不理解mulTab在做什么,所以我直接写了相同的函数。

package main

import "fmt"

type UserInput struct {
    	Lines   int
    	Columns int
}

func readUserInput() *UserInput {
	userInput := UserInput{}

	fmt.Println("Lines:")
	fmt.Scan(&userInput.Lines)
	fmt.Println("Columns:")
	fmt.Scan(&userInput.Columns)

	return &userInput
}

func mulTab(lin, col int) {
	var result int
	for lines := 1; lines <= lin; lines++ {
		for columns := 1; columns <= col; columns++ {
			result = columns * lines
			fmt.Println(columns, "x", lines, "=", result)
		}
	}
}

func main() {
	userInput := readUserInput()

	mulTab(userInput.Lines, userInput.Columns)
}

回答

1. 第一个问题

你的代码基本正确,但有几个小问题需要修正:

func readInput() {
    var lines, columns int
    fmt.Print("Lines: ")
    fmt.Scan(&lines)
    fmt.Print("Columns: ")
    fmt.Scan(&columns)

    mulTab(lines, columns) // 正确传递值
}

func mulTab(lin, col int) int {
    var result int
    
    for lines := 1; lines <= lin; lines++ { // 需要声明lines变量
        for columns := 1; columns <= col; columns++ { // 需要声明columns变量
            result = columns * lines
            fmt.Println(columns, "x", lines, "=", result)
        }
    }
    return result
}

mulTab 函数中传递参数是标准做法。更好的做法可能是让 readInput 返回读取的值,由调用者决定如何处理:

func readInput() (int, int) {
    var lines, columns int
    fmt.Print("Lines: ")
    fmt.Scan(&lines)
    fmt.Print("Columns: ")
    fmt.Scan(&columns)
    return lines, columns
}

func main() {
    lines, columns := readInput()
    mulTab(lines, columns)
}

2. 第二个问题

main() 中传递函数返回值作为参数是常见的做法。关于文件关闭的问题:

func readDir() (*os.File, error) {
    f, err := os.Open(".")
    if err != nil {
        return nil, err
    }
    return f, nil
}

func listDir(s *os.File) ([]string, error) {
    defer s.Close() // 在这里关闭更合适
    
    list, err := s.Readdirnames(0)
    if err != nil {
        return nil, err
    }
    
    for _, name := range list {
        fmt.Println(name)
    }
    return list, nil
}

func main() {
    f, err := readDir()
    if err != nil {
        log.Fatal(err)
    }
    list, err := listDir(f)
    if err != nil {
        log.Fatal(err)
    }
    _ = list // 使用返回的列表
}

可以在一个函数中打开文件,在另一个函数中关闭。关键是确保文件在使用完毕后被关闭。

3. 第三个问题

有几种方法可以处理这个问题:

方法1:返回文件名

func create(filename string) (string, error) {
    f, err := os.Create(filename)
    if err != nil {
        return "", err
    }
    f.Close() // 立即关闭,只创建文件
    return filename, nil
}

func write(filename string, data []byte) error {
    return ioutil.WriteFile(filename, data, 0644)
}

func main() {
    filename := "test.txt"
    
    // 创建文件
    _, err := create(filename)
    if err != nil {
        log.Fatal(err)
    }
    
    // 写入内容
    data := []byte("Hello, World!")
    err = write(filename, data)
    if err != nil {
        log.Fatal(err)
    }
}

方法2:返回文件句柄

func create(filename string) (*os.File, error) {
    return os.Create(filename)
}

func write(f *os.File, data []byte) error {
    defer f.Close()
    _, err := f.Write(data)
    return err
}

func main() {
    filename := "test.txt"
    
    // 创建并获取文件句柄
    f, err := create(filename)
    if err != nil {
        log.Fatal(err)
    }
    
    // 使用文件句柄写入
    data := []byte("Hello, World!")
    err = write(f, data)
    if err != nil {
        log.Fatal(err)
    }
}

方法3:使用os.OpenFile

func writeToFile(filename string, data []byte) error {
    f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
    if err != nil {
        return err
    }
    defer f.Close()
    
    _, err = f.Write(data)
    return err
}

func main() {
    filename := "test.txt"
    data := []byte("Hello, World!")
    
    err := writeToFile(filename, data)
    if err != nil {
        log.Fatal(err)
    }
}

将代码拆分成小函数是好的实践,可以提高代码的可读性和可维护性。关键是要清晰地定义每个函数的职责和参数传递方式。

回到顶部