Go의 구조체 필드에 Interface 변수와 포인터 변수를 설정할 때 참조하는 관계를 알고 싶습니다 2

22089 단어 Gotech

개시하다


예전에 썼는데구조 필드 변수의 덮어쓰기 동작 보충하고 싶어서 추가 기재해야 해요.
어떤 말을 추가로 쓰려면 필드의 구조체 중의 필드가 Setter 등에 의해 변경되었을 때의 행동에 관한 것이다.
어디가 지침이고 어디가 실체인지 알면 경험에서'어떻게 움직이는지'를 알 수 있을 것 같아요.
실제로 이쪽은 상황으로 발생하는 경우가 많아서 서류로 남기고 싶어요.
구조체에 상태가 있다면 그 자체의 범위와 상태 변경이 가져온 영향을 다시 한 번 확인하고 싶습니다.
(그리고 Go의 Interface가 실체인지 지침인지 아직 직관적으로 이해하지 못했다)
동작 환경은 전번(위 참조)과 같습니다.

컨텐트


다음 모드를 확인합니다.
  • 구조 필드에 설정된Interface의 필드 변수가Setter에서 정보를 다시 쓰는 경우
  • 구조 필드에 설정된Interface의 원시 변수가 Setter를 통해 정보를 다시 쓰는 경우
  • 구조체의 필드에 설정된 바늘의 필드 변수가 Setter를 통해 정보를 다시 쓰는 경우
  • 구조 필드에 설정된 바늘의 원시 변수가 Setter를 통해 정보를 다시 쓰는 경우
  • 구조 정의 사용


    마지막으로 사용한 시간을 반환하는 Interface Mutable Clock 및 설치된 Mutable Clock
    이번에는 세트에서 구조체의 영역을 변경할 수 있다.
    Mutable Clock/Mutable Clock Mock에 필드 변수가 있는 구조 Mutable Sample을 가정합니다.
    type MutableClock interface {
    	Now() int
    	Setter(value int)
    }
    
    type MutableClockMock struct {
    	value int
    }
    
    func (cm *MutableClockMock) Now() int {
    	return cm.value
    }
    
    func (cm *MutableClockMock) Setter(value int) {
    	cm.value = value
    }
    
    type MutableSample struct {
    	Clock *MutableClockMock
    }
    
    type MutableSample0 struct {
    	Clock MutableClock
    }
    

    구조 필드에 설정된 Interface의 필드 변수가 Setter를 통해 정보를 다시 쓸 때


    func TestApp_Interface_mutable(t *testing.T) {
    	clock := MutableClockMock{10}
    	struct1 := MutableSample0{Clock: &clock}
    	struct2 := MutableSample0{Clock: &clock}
    
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, &struct1.Clock, &struct2.Clock)
    	// struct1 のフィールド変数を Setter で変更
    	struct1.Clock.Setter(100)
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, &struct1.Clock, &struct2.Clock)
    }
    /*
    === RUN   TestApp_Interface_mutable
    struct1 now=[10], struct2 now=[10].
    base addres=[0xc000022a00], struct1 address=[0xc00004b460], struct2 address=[0xc00004b470].
    struct1 now=[100], struct2 now=[100].
    base addres=[0xc000022a00], struct1 address=[0xc00004b460], struct2 address=[0xc00004b470].
    --- PASS: TestApp_Interface_mutable (0.00s)
    */
    
    Setter를 통해 구조 1의 필드 변수 값을 변경하면 구조 2의 필드 변수에도 영향을 미친다.
    변수의 주소는 모두 다르지만 인용 목표가 같기 때문에 영향도 파급된다.

    구조 필드에 설정된 Interface의 원래 변수가 Setter를 통해 정보를 다시 쓸 때


    func TestApp_Interface_OverrideBase_mutable(t *testing.T) {
    	clock := &MutableClockMock{10}
    	struct1 := MutableSample0{Clock: clock}
    	struct2 := MutableSample0{Clock: clock}
    
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, &struct1.Clock, &struct2.Clock)
    	// 代入元のフィールド変数を Setter で変更
    	clock.Setter(100)
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, &struct1.Clock, &struct2.Clock)
    }
    /*
    === RUN   TestApp_Interface_OverrideBase_mutable
    struct1 now=[10], struct2 now=[10].
    base addres=[0xc00004b4c0], struct1 address=[0xc00004b4d0], struct2 address=[0xc00004b4e0].
    struct1 now=[100], struct2 now=[100].
    base addres=[0xc00004b4c0], struct1 address=[0xc00004b4d0], struct2 address=[0xc00004b4e0].
    --- PASS: TestApp_Interface_OverrideBase_mutable (0.00s)
    */
    
    Setter에서 구조 1, 2의 필드 변수의 원시 변수를 변경하면 구조 1, 2의 필드 변수에도 영향을 미친다.
    변수의 주소도 각기 다르지만 참조 목표가 같기 때문에 영향도 영향을 미친다.

    구조 필드에 설정된 포인터 필드 변수가 Setter를 통해 정보를 다시 쓸 때


    func TestApp_Pointer_mutable(t *testing.T) {
    	clock := MutableClockMock{10}
    	struct1 := MutableSample{Clock: &clock}
    	struct2 := MutableSample{Clock: &clock}
    
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, struct1.Clock, struct2.Clock)
    	// struct1 のメンバー変数を Setter で変更
    	struct1.Clock.Setter(100)
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, struct1.Clock, struct2.Clock)
    }
    /*
    === RUN   TestApp_Pointer_mutable
    struct1 now=[10], struct2 now=[10].
    base addres=[0xc000022a40], struct1 address=[0xc000022a40], struct2 address=[0xc000022a40].
    struct1 now=[100], struct2 now=[100].
    base addres=[0xc000022a40], struct1 address=[0xc000022a40], struct2 address=[0xc000022a40].
    --- PASS: TestApp_Pointer_mutable (0.00s)
    */
    
    Setter를 통해 구조 1의 필드 변수 값을 변경하면 구조 2의 필드 변수에도 영향을 미친다.
    변수의 주소가 모두 같아서 모든 변수에 영향을 줍니다.

    구조 필드에 설정된 포인터의 원래 변수가 Setter를 통해 정보를 다시 쓸 때


    func TestApp_PointerOverride_mutable(t *testing.T) {
    	clock := MutableClockMock{10}
    	struct1 := MutableSample{Clock: &clock}
    	struct2 := MutableSample{Clock: &clock}
    
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, struct1.Clock, struct2.Clock)
    	// 代入元の変数を Setter で変更
    	clock.Setter(100)
    	fmt.Printf("struct1 now=[%d], struct2 now=[%d].\n", struct1.Clock.Now(), struct2.Clock.Now())
    	fmt.Printf("base addres=[%p], struct1 address=[%p], struct2 address=[%p].\n", &clock, struct1.Clock, struct2.Clock)
    }
    /*
    === RUN   TestApp_PointerOverride_mutable
    struct1 now=[10], struct2 now=[10].
    base addres=[0xc000022a60], struct1 address=[0xc000022a60], struct2 address=[0xc000022a60].
    struct1 now=[100], struct2 now=[100].
    base addres=[0xc000022a60], struct1 address=[0xc000022a60], struct2 address=[0xc000022a60].
    --- PASS: TestApp_PointerOverride_mutable (0.00s)
    */
    
    Setter에서 구조 1, 2의 필드 변수의 원시 변수를 변경하면 구조 1, 2의 필드 변수에도 영향을 미친다.
    변수의 주소가 모두 같아서 모든 변수에 영향을 줍니다.

    총결산


    결실


    Interface 또는 인터페이스에 관계없이 구조 필드 변수의 선언은
    원래 변수(구성체)가 같으면 Setter의 상태 변경은 참조된 모든 구성체에 영향을 줍니다.
    참조된 필드 변수 자체가 Interface에서 참조하는 엔티티 값의 주소와 같기 때문입니다.
    그 자체가 변경되면 참조 대상의 값이 모두 변경됩니다.

    감상


    만약 필드 변수가 바늘 변수 등과 관련이 있다면
    Setter 등에서 변경한 뒤 같은 참고를 사용했을 경우 변경도 영향을 미칠 수 있음을 재확인했다(아는 사람에게는 당연한 일일 수 있다).
    변수의 변경으로 인해 예상치 못한 동작을 피하려면
    필드 변수에 포인터 변수를 전달할 때 다음과 같은 의식이 효과가 있을 수 있습니다.
  • 패브릭에 상태 없음
  • 같은 변수를 필드로 전달하지 않으려고
  • 필드를 고쳐야 하는 상황에서 변수의 참조 범위와 고쳐 쓰기 범위를 명확히 파악
  • 좋은 웹페이지 즐겨찾기