-2

リーダー インターフェイスについて質問があります。定義は次のようになります。

type Reader interface {
    Read(p []byte) (n int, err error)
}

リーダー インターフェイスを使用する次のコードがあります。

package main

import (
    "fmt"
    "os"
)

// Reading files requires checking most calls for errors.
// This helper will streamline our error checks below.
func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {

    // You'll often want more control over how and what
    // parts of a file are read. For these tasks, start
    // by `Open`ing a file to obtain an `os.File` value.
    f, err := os.Open("configuration.ini")
    check(err)

    // Read some bytes from the beginning of the file.
    // Allow up to 5 to be read but also note how many
    // actually were read.
    b1 := make([]byte, 10)
    n1, err := f.Read(b1)
    check(err)
    fmt.Printf("%d bytes: %s\n", n1, string(b1))

    f.Close()

}

上記のコードからわかるように、はバイト スライスとして定義され、値引数としてメソッドb1に渡されます。メソッドのRead後に、ファイルからの最初の 10 文字が含まれます。 Readb1

上記のコードについて私が非常に混乱しているのは、メソッド b1の後に突然値が含まれるのはなぜですか。Read

Golang では、値をメソッドに渡すと、参照ではなく値として渡されます。私が話していることを明確にするために、サンプルアプリケーションを作成しました。

package main


import (
    "fmt"
)

func passAsValue(p []byte) {
    c := []byte("Foo")
    p = c
}

func main() {

    b := make([]byte, 10)
    passAsValue(b)
    fmt.Println(string(b))
}

passAsValue関数の後、b値が含まれておらず、golang で期待していたように、引数は値として関数またはメソッドに渡されます。

では、最初のコード スニペットが渡された引数の内容を変更できるのはなぜでしょうか。Readメソッドがスライスのポインターを期待する場合、[]byte私は同意しますが、この場合はそうではありません。

4

3 に答える 3

0

でポインタを渡すのとまったく同じ動作ですC

#include <stdio.h>
#include <stdlib.h>

// p is passed by value ; however, this function does not modify p,
// it modifies the values pointed by p.
void read(int* p) {
    int i;
    for( i=0; i<10; i++) {
        p[i] = i+1;
    }
}

// p is passed by value, so changing p itself has no effect out
// of the function's scope
void passAsValue(int*p) {
   int* c = (int*)malloc(3*sizeof(int));

   c[0] = 15; // 'F' in hex is 15 ...
   c[1] = 0;
   c[2] = 0;

   p = c;
}

int main() {
    int* p = (int*)malloc(10*sizeof(int));
    int i;
    for( i=0; i<10; i++) {
        p[i] = 0;
    }

    printf("             init : p[0] = %d\n", p[0]);

    read(p);
    printf("       after read : p[0] = %d\n", p[0]);

    passAsValue(p);
    printf("after passAsValue : p[0] = %d\n", p[0]);

    return 0;
}

出力:

//             init : p[0] = 0
//       after read : p[0] = 1
//after passAsValue : p[0] = 1 // <- not 15, the modification from
//                             //    within passAsValue is not persistent

(記録のために:このCプログラムはint* c配列をリークします)

スライスには、ポインターだけでなく、より多くのGo情報が含まれています。これは、ポインター、長さ、および割り当てられた配列の最大容量を含む小さな構造体です (他の回答で言及されているリンクを参照してください: https://blog.golang.org /スライス)。ただし、コードの観点からは、ポインタ
とまったく同じように動作します。C

于 2015-04-29T08:08:14.963 に答える