草庐IT

pointers - Golang : help understanding pointers, 分配和意外行为

coder 2024-07-05 原文

所以我带着更多初学者的问题回来了,这些问题我似乎无法全神贯注。 我正在试验以下代码。

func main() {
start := time.Now()
var powers []*big.Int
for i := 1; i < 1000; i++ {
    I := big.NewInt(int64(i))
    I.Mul(I, I)
    powers = append(powers, I)
}
fmt.Println(powers)
fmt.Println(time.Since(start))
start = time.Now()
var seqDiffs []*big.Int
diff := new(big.Int)
for i, v := range powers {
    if i == len(powers)-2 {
        break
    }
    diff = v.Sub(powers[i+1], v)
    seqDiffs = append(seqDiffs, diff)
}
fmt.Println(seqDiffs)
fmt.Println(time.Since(start))
}

我的意图是按以下方式将 Sub() 的结果分配给 diff

diff.Sub(powers[i+1], v)

然而,这导致 seqDiffs 的值为 1995(正确的最后一个值)一遍又一遍地重复。我知道这很可能是因为 seqDiffs 只是指向相同内存地址的指针列表,但我不明白的是为什么下面的工作正常

v.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, v)

这导致 seqDiffs 成为从 3 到 1995 的所有奇数的列表,这是正确的,但这本质上不仍然是指向相同内存地址的指针列表吗? 另外,为什么以下是正确的,它也应该导致 seqDiffs 也是指向相同内存地址的指针列表?

diff = v.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, diff)

我也尝试过以下方式

diff := new(*big.Int)
for i, v := range powers {
if i == len(powers)-2 {
    break
}
diff.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, diff)
}

但是从ide收到了这些错误:

*./sequentialPowers.go:26: calling method Sub with receiver diff (type **big.Int) requires explicit dereference
./sequentialPowers.go:27: cannot use diff (type **big.Int) as type *big.Int in append*

我将如何进行“显式”取消引用?

最佳答案

在调试 Go 中的指针问题时,了解发生了什么的一种方法是使用 fmt.Printf 使用 %p 打印感兴趣变量的内存地址.

关于你的第一个问题,为什么将 diff.Sub(powers[i+1], v) 的结果附加到你的 *big.Int 产生一个 slice ,其中每个索引都是相同的值 - 您正在更新分配给 diff 的内存地址处的值,并将该指针的副本附加到 slice 。因此, slice 中的所有值都是指向相同值的指针。

打印diff 的内存地址将证明是这种情况。填充 slice 后 - 执行以下操作:

for _, val := range seqDiffs {
    fmt.Printf("%p\n", val) // when i ran this - it printed 0xc4200b7d40 every iteration
}

在您的第二个示例中,值 v 是指向位于不同地址的 big.Int 的指针。您正在将 v.Sub(..) 的结果分配给 diff,这会更新 diff 指向的基础地址。因此,当您将 diff 附加到 slice 时,您是在唯一地址处附加了一个指针的副本。使用 fmt.Printf 你可以看到这样 -

var seqDiffs []*big.Int
diff := new(big.Int)
for i, v := range powers {
    if i == len(powers)-2 {
        break
    }
    diff = v.Sub(powers[i+1], v)
    fmt.Printf("%p\n", diff) // 1st iteration 0xc4200109e0, 2nd 0xc420010a00, 3rd 0xc420010a20, etc
    seqDiffs = append(seqDiffs, diff)
} 

关于你的第二个问题——在 Go 中使用 new 关键字分配指定类型的内存但不初始化它 ( check the docs )。在您的情况下,对 new 的调用会分配一种指向 big.Int (**big.Int) 的指针,因此编译器错误提示您不能在调用 append 时使用此类型。

要显式取消引用 diff 以便在其上调用 Sub,您必须将代码修改为以下内容:

(*diff).Sub(powers[i+1], v)

在 Go 中,选择器表达式为您取消引用指向结构的指针,但在这种情况下,您是在指向指针的指针上调用方法,因此您必须显式取消引用它。

可以找到有关在 Go 中调用结构(选择器表达式)方法的非常有用的读物​​ here

并将其添加到 slice 中

seqDiffs = append(seqDiffs, *diff)

关于pointers - Golang : help understanding pointers, 分配和意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44087509/

有关pointers - Golang : help understanding pointers, 分配和意外行为的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  5. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  6. ruby-on-rails - Ruby 中意外的大小写行为 - 2

    我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。

  7. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

  8. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  9. ruby-on-rails - 使用 Dragonfly 从 URL 分配图像 - 2

    我正在使用Dragonfly在Rails3.1应用程序上处理图像。我正在努力通过url将图像分配给模型。我有一个很好的表格:{:multipart=>true}do|f|%>RemovePicture?Dragonfly的文档指出:Dragonfly提供了一个直接从url分配的访问器:@album.cover_image_url='http://some.url/file.jpg'但是当我在控制台中尝试时:=>#ruby-1.9.2-p290>picture.image_url="http://i.imgur.com/QQiMz.jpg"=>"http://i.imgur.com/QQ

  10. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

随机推荐