2015-04-05 2 views
2

Я писал программу, которая считывает данные из io.Reader и кэширует их в байтах.Buffer.В чем разница между типами приемника-указателя и значения?

type SecureReader struct { 
    pipe  io.Reader 
    shared *[32]byte 
    decrypted bytes.Buffer 
} 

func (s SecureReader) Read(b []byte) (int, error) { 
    s.decryptPipeIntoBuffer() 
    return s.decrypted.Read(b) 
} 

func (s SecureReader) decryptPipeIntoBuffer() (int, error) {/*Lots of code...*/} 

Я сначала использовал приемник ценностей, потому что я думал, что они были такими же. Тем не менее, я заметил, что мой метод не делает ничего при вызове: SecureReader.Read() всегда будет возвращать io.EOF.

Я ударился головой вокруг и изменил тип приемника для

func (s *SecureReader) decryptPipeIntoBuffer() (int, error) {/*Lots of code...*/} 

Теперь мой код волшебно работает. Что происходит?

ответ

2

Приемопередатчик значений действует по копиям экземпляра SecureReaders.

Если метод мутирует какую-либо часть копии экземпляра (например, изменить s.decrypted), она не видна на оригинальном экземпляре приемника, после выхода метода.

Это изменяет с приемником указателя, где метод работает и может мутирует фактический SecureReader экземпляр s, так как копия указателя передается методу.


Другие примеры в "Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang".

Проще говоря: вы можете обращаться с получателем, как если бы это был аргумент, передаваемый методу. Все те же причины, по которым вы, возможно, захотите пройти по значению или пройти по ссылке, применимы.

причин, почему вы хотели бы пройти по ссылке, а не по значению:

  • Вы действительно хотите изменить приемник («чтение/запись», а не просто «читать»)
  • В struct очень большой и глубокая копия стоит дорого
  • Согласованность: если некоторые из методов в структуре имеют указатели-указатели, то остальное тоже должно быть. Это позволяет прогнозировать поведение

Если вам нужны эти характеристики при вызове метода, используйте приемник указателя.

+0

Означает ли это каждый раз, когда я вызываю Read(), будет передан новый SecureReader? Почему io.Reader налагает такое неудобное ограничение? –

+1

@SomeNoobStudent интерфейс содержит указатель на данные, поэтому копирование интерфейса не имеет большого значения. Копирование структуры, в другой руке, является тем, что предотвращает изменчивость. – VonC

+0

OH! Как просвещать! Спасибо огромное! Душевая с авокатами. –

Смежные вопросы