Home 3. interface
Post
Cancel

3. interface

Go/Golang - Interface

Interface 기본

Interface 선언 형태

1
2
3
4
5
6
7
8
9
  // type  interface_name   interface_keyword
  type employeeInterface interface {
    Work()
    Rest(hour int) int
    // method 선언 시 주의사항
    // 1 메서드는 반드시 메서드명이 있어야 한다.
    // 2 Overload 안된다. 
    // 3 인터페이스에서는 메서드 구현을 포함하지 않는다.
  }

Interface 사용이유

  • Interface 를 사용하면 구체적으로 구현한 객체가 아닌, Interface 만으로 메소드를 호출할 수 있다. 따라서 필요에 따라 객체를 갈아 끼우기 용이하다. 또한 그 과정에서 발생하는 코드의 수정량도 매우 적어지며, 이 Interface를 사용하는 로직 입장에서는 안에 어떤 객체가 들어오는 지 알아야 할 필요 없이 코드를 유연하게 사용할 수 있다.
  • Interface 는 이런 측면에서 Abstraction Layer(추상화 계층) 이다. 또한 이러한 계층을 통해 서비스 제공자서비스 사용자간의 연결고리를 끊는 것을 decoupling(디 커플링) 이라고 한다.

Interface 추가 기능

Inner Interface

Interface 안에 Interface를 인자로 가질 수 있다. 하지만 구현체가 Interface 안의 모든 메소드를 구현해야지 만이 그 Interface로 사용될 수 있다는 점을 명심하자!

빈 Interface {} 는 어디다 쓰나?

빈 Interface인 interface{} 는 어떤 값이는 받을 수 있는 함수, 메소드 등을 만들 때 사용한다. 예를 들어 함수의 인자로 빈 interface를 받으면, 해당 interface의 타입에 따라 다른 로직이 동작하게 만들수 도 있다.

Interface의 기본값

nil 값이다. 따라서 Interface를 사용할 때에는 nil값인지 여부를 꼭 확인하고 사용해야한다.

Interface 변환

Interface를 다른 타입으로 변환하기

Interface 본래의 구체화된 타입으로 복원하는 경우 많이 사용한다. 만약 같은 interface를 공유하는 다른 개체를 원 객체로 되돌렸는데, 해당 인터페이스가 *Student를 가르키지 않거나, 구현하고있지 않아도 에러가 발생한다. 즉, 내부적으로 어떤 인스턴스를 가르키고 있었는지 또한 중요한 문제이다.

1
2
  var testItf Interface
  origin := testItf.(beforeType)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
type Stringer interface{
	String() string
}

type Student struct{
	Age int
}

func (s *Student) String() string {
	return fmt.Sprintf("Student Age: %d", s.Age)
}

func PrintAge(stringer Stringer){
	s := stringer.(*Student)
	fmt.Printf("age : %d\n", s.Age)
}

func main(){
	// Student 구조체 초기화.
	s := &Student{15}
	// PrintAge함수 호출
	// Stringer 인터페이스 변수인 s를 -> Struct로 변환해 -> Age로 접근하고자 함.
	// (Stringer 인터페이스는 Age를 가지고 있지 않기 때문에 본래 타입인 Struct로 변환하지 않으면 접근불가)
	// stringer 변수 내부에서 *Student를 가리키고 있으므로 무사히 변환 가능
  // 만약 같은 interface를 공유하는 다른 개체를 원 객체로 되돌렸는데, 해당 인터페이스가 *Student를 가르키지 않거나, 
  // 구현하고있지 않아도 에러가 발생한다. -> 즉 내부적으로 어떤 인스턴스를 가르키고 있었는지 또한 중요한 문제이다.
	PrintAge(s)
}

Interface를 다른 인터페이스로 타입변환하기

인터페이스가 인터페이스로 변환하는 경우에는 변경 전 인터페이스를 포함하지 않아도 된다. 하지만 변경하려고 하는 인터페이스를 근본 인터페이스가 포함하고 있는 상태여야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  package main

  type Reader interface{
    Read()
  }

  type Closer interface{
    Close()
  }

  type File struct{	
  }

  func(f *File) Read(){
  }

  // func(f *File) Close(){
  // }

  func ReadFile(reader Reader){
    c := reader.(Closer)
    c.Close()

    // sol 1.
    // c, ok := reader.(Closer)

    // if ok{
    //   c.Close()
    // }

    // sol 2.
    // if c, ok := reader.(Closer); ok{
    // 	c.Close()
    // }
  }

  func main(){
    file := &File{}
    ReadFile(file)
  }

Questions

Q1. Interface를 사용하는 이유는 무엇인가.

1
2
3
4
  Interface  사용하면 `구체적으로 구현한 객체가 아닌, Interface` 만으로 메소드를 호출할  있다. 
  따라서 필요에 따라 객체를 갈아 끼우기 용이하다. 또한  과정에서 발생하는 코드의 수정량도 매우 적어지며, 
   `Interface를 사용하는 로직` 입장에서는 안에 어떤 객체가 들어오는  알아야  필요 없이 코드를 
  유연하게 사용할  있다 (Abstraction Layer 이자 Decoupling 작용)

Q2. Duck-typing이란 무엇인지, 또 장점은 무엇인지 설명하라.

1
2
3
4
5
  Interface 구현 여부를 타입 선언 시점에 명시적으로 나타낼 필요없이, 인터페이스에 정의한 메서드의 포함여부 만으로 
  특정 인터페이스를 포함하는지 여부를 결정하는 . `Duck-typing`  지원하지 않았다면 java와 같이 특정 클래스가 
  어떤 인터페이스를 구현하고 있는지를 표시해야 했다.  부분은 `인터페이스 지원 여부를 사용자가 아닌, 제공 대상자가 
  직접 작성해야 했으므로 사용자 중심의 코딩이 불가능했다.`  부분을 사용자 중심 , 인터페이스 적용여부를 사용자가
  선택할  있도록 구성된 환경이 바로 `Duck-Typing` 이다.

Q3. 아래 코드를 에러가 발생하지 않도록 고쳐라.

추가로, 런타임 에러를 잡을수 있는 형태의 코드도 추가하라.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  package main

  type Reader interface{
    Read()
  }

  type Closer interface{
    Close()
  }

  type File struct{	
  }

  func(f *File) Read(){
  }

  // func(f *File) Close(){
  // }

  func ReadFile(reader Reader){
    c := reader.(Closer)
    c.Close()

    // sol 1.
    // c, ok := reader.(Closer)

    // if ok{
    //   c.Close()
    // }

    // sol 2.
    // if c, ok := reader.(Closer); ok{
    // 	c.Close()
    // }
  }

  func main(){
    file := &File{}
    ReadFile(file)
  }
This post is licensed under CC BY 4.0 by the author.