Golang新手-对指针感到困惑,请帮助转换c++;要去的片段

Golang新手-对指针感到困惑,请帮助转换c++;要去的片段,go,Go,我是刚来戈兰的新手,正在慢慢学习。为了学习,我选择将这段算法转换为golang“”。 我已经尽了最大努力,但戈兰指针比C++更让人迷惑。 我尝试了很多不同的方法让它工作,但指针的东西仍然让我感到不安。我就是不能让下面提到的两个函数正常工作。有时输出为-未找到解决方案。有时,它只输出不变的网格。 有人可以修复SolveSudoku()和FindUnassignedLocation()函数(以及其他任何函数,如果有的话),并解释如何在GO中使用引用和指针。 我还试着阅读GO网站上的一些文档,但这并不

我是刚来戈兰的新手,正在慢慢学习。为了学习,我选择将这段算法转换为golang“”。 我已经尽了最大努力,但戈兰指针比C++更让人迷惑。 我尝试了很多不同的方法让它工作,但指针的东西仍然让我感到不安。我就是不能让下面提到的两个函数正常工作。有时输出为-未找到解决方案。有时,它只输出不变的网格。
有人可以修复SolveSudoku()和FindUnassignedLocation()函数(以及其他任何函数,如果有的话),并解释如何在GO中使用引用和指针。
我还试着阅读GO网站上的一些文档,但这并不是很好,而且我没有足够的经验来理解其中给出的非常小的内容。
如果有人建议在这段代码中还有一些可以改进的地方,我也会非常感激,bugs,错误?什么都可以

package main

import "fmt"

const (
    UNASSIGNED = 0
    N          = 9
)

func SolveSudoku(grid [N][N]int) bool {
    var row, col int
    if !FindUnassignedLocation(grid, row, col) {
        return true
    }
    for num := 1; num <= 9; num++ {
        if isSafe(grid, row, col, num) {
            grid[row][col] = num
            if SolveSudoku(grid) {
                return true
            }
            grid[row][col] = UNASSIGNED
        }
    }
    return false
}

func FindUnassignedLocation(grid [N][N]int, row int, col int) bool {
    for row = 0; row < N; row++ {
        for col = 0; col < N; col++ {
            if grid[row][col] == UNASSIGNED {
                return true
            }
        }
    }
    return false
}

func UsedInRow(grid [N][N]int, row int, num int) bool {
    for col := 0; col < N; col++ {
        if grid[row][col] == num {
            return true
        }
    }
    return false
}

func UsedInCol(grid [N][N]int, col int, num int) bool {
    for row := 0; row < N; row++ {
        if grid[row][col] == num {
            return true
        }
    }
    return false
}

func UsedInBox(grid [N][N]int, boxStartRow int, boxStartCol int, num int) bool {
    for row := 0; row < 3; row++ {
        for col := 0; col < 3; col++ {
            if grid[row+boxStartRow][col+boxStartCol] == num {
                return true
            }
        }
    }
    return false
}

func isSafe(grid [N][N]int, row int, col int, num int) bool {
    return !UsedInRow(grid, row, num) && !UsedInCol(grid, col, num) && !UsedInBox(grid, row-row%3, col-col%3, num)
}

func printGrid(grid [N][N]int) {
    for row := 0; row < N; row++ {
        for col := 0; col < N; col++ {
            fmt.Printf("%2d", grid[row][col])
        }
        fmt.Printf("\n")
    }
}

func main() {
    var grid = [N][N]int{
        [N]int{3, 0, 6, 5, 0, 8, 4, 0, 0},
        [N]int{5, 2, 0, 0, 0, 0, 0, 0, 0},
        [N]int{0, 8, 7, 0, 0, 0, 0, 3, 1},
        [N]int{0, 0, 3, 0, 1, 0, 0, 8, 0},
        [N]int{9, 0, 0, 8, 6, 3, 0, 0, 5},
        [N]int{0, 5, 0, 0, 9, 0, 6, 0, 0},
        [N]int{1, 3, 0, 0, 0, 0, 2, 5, 0},
        [N]int{0, 0, 0, 0, 0, 0, 0, 7, 4},
        [N]int{0, 0, 5, 2, 0, 6, 3, 0, 0},
    }

    if SolveSudoku(grid) == true {
        printGrid(grid)
    } else {
        fmt.Printf("No solution exists")
    }

    return
}
主程序包
输入“fmt”
常数(
未分配=0
N=9
)
func数独(网格[N][N]int)布尔{
变量行,列int
if!FindUnassignedLocation(网格、行、列){
返回真值
}

对于num:= 1;Num < P>你的问题并不是你不理解指针。指针在C++中的运行方式与C++一样(除了GO有逃避分析和GCS之类的东西,你不必担心悬空或无效指针,而没有指针运算的可疑代价)。 <>你的问题是C++和GO数组之间的差异,在C++中,数组是指针,语法是别名。
int*a
是同一种类型,静态大小调整和自由初始化只是一个很酷的编译器技巧。访问数组是指针算术的奇特语法,然后是解引用——正如前面提到的,这是Go没有的

在Go中,数组是而不是指针。当你有一个接受
a[9]int的函数时,你实际上是在告诉编译器复制九个整数值,而不是指向内存中恰好有九个整数值的位置的指针。想想
func(a[2]int)
是编写
func(a1,a2int)
的好方法

这也导致了另一个微妙的代码差异,在C++ +Calp>int中,[9 ] [9 ] 是指向九个指针的指针,每个指针指向九个INT。 Go中有两个简单的解决方案:

  • 使用指向数组的指针。如在
    grid*[N][N]int
    中一样。这可以正常工作,但在数组中访问和存储内容有点不干净。您必须使用
    (*grid)[i][j]
    来显式取消对指针的引用,该指针看起来很难看,可能有点难以读取

  • 使用切片。这是更好的选择,也是更惯用的Go样式。它还避免了到处都是讨厌的全局常量。折衷是,您确实牺牲了一些关于列大小的先验保证

  • 我将用带有注释的切片重写几个方法,剩下的留给您:

    func main() {
        // We can omit the []int on every line, Go infers it
        var grid = [][]int{
            {3, 0, 6, 5, 0, 8, 4, 0, 0},
            {5, 2, 0, 0, 0, 0, 0, 0, 0},
            {0, 8, 7, 0, 0, 0, 0, 3, 1},
            {0, 0, 3, 0, 1, 0, 0, 8, 0},
            {9, 0, 0, 8, 6, 3, 0, 0, 5},
            {0, 5, 0, 0, 9, 0, 6, 0, 0},
            {1, 3, 0, 0, 0, 0, 2, 5, 0},
            {0, 0, 0, 0, 0, 0, 0, 7, 4},
            {0, 0, 5, 2, 0, 6, 3, 0, 0},
        }
    
        // == true is superfluous
        if SolveSudoku(grid) {
            printGrid(grid)
        } else {
            fmt.Println("No solution exists")
        }
    
        // Don't need to explicitly return, Go's mains are "void"
    }
    
    
    func UsedInCol(grid [][]int, col int, num int) bool {
        // We can use range to iterate over the whole slice.
        // The first value (which we ignore) is the slice index, the value you
        // used to call "row".
        // Now row is the slice containing the given row, this is similar to an iterator.
        for _,row := range grid {
            if row[col] == num {
                return true
            }
        }
        return false
    }
    
    杂项说明:

  • 以前使用常量
    N
    时,现在可以使用
    len(网格)
    。要获取列的长度,请使用
    len(网格[0])
    (警告:确保
    grid[0]
    存在)

  • 由于它是一个值,因此将
    [N][N]int
    作为参数或返回值几乎总是效率低下,因为每次函数调用时它都是一个相当大的副本。指针跟踪通常更快,但N值非常小(可能是1-2)

  • Go中不存在引用,除非在非常技术的意义上,如闭合变量的行为

  • 更好的方法是使用某种At/Set方法Set声明类似于
    类型SudokuGrid struct{grid[]int;rows,cols int}
    的东西,这可以让您获得一些大小保证。我将把这件事留给您(或者这是否是一个好主意)


  • 你的问题并不是你不理解指针。指针在C++中的运行方式和C++一样(除了GO有逃避分析和GCS之类的东西,你不用担心指针或指针无效,在没有指针运算的可疑成本下)。 <>你的问题是C++和GO数组之间的差异,在C++中,数组是指针,语法是别名。

    int*a
    是同一种类型,静态大小调整和自由初始化只是一个很酷的编译器技巧。访问数组是指针算术的奇特语法,然后是解引用——正如前面提到的,这是Go没有的

    在Go中,数组是而不是指针。当你有一个接受
    a[9]int的函数时,你实际上是在告诉编译器复制九个整数值,而不是指向内存中恰好有九个整数值的位置的指针。想想
    func(a[2]int)
    是编写
    func(a1,a2int)
    的好方法

    这也导致了另一个微妙的代码差异,在C++ +Calp>int中,[9 ] [9 ] 是指向九个指针的指针,每个指针指向九个INT。 Go中有两个简单的解决方案:

  • 使用指向数组的指针。如在
    grid*[N][N]int
    中一样。这可以正常工作,但在数组中访问和存储内容有点不干净。您必须使用
    (*grid)[i][j]
    来显式取消对指针的引用,该指针看起来很难看,可能有点难以读取

  • 使用切片。这是更好的选择,更惯用的围棋风格。它还避免了到处都是讨厌的全局常量。权衡是