Go: Métodos e interfaces do Go

Última atualização: 2026-08-26

Um método é uma função que recebe um receptor, e uma interface é um conjunto de assinaturas de métodos — o Go implementa a “abstração comportamental” orientada a objetos com uma sintaxe concisa, sem a complexidade da herança de classes.

O Go não possui classes, mas possui métodos; não possui a palavra-chave implements, mas possui interfaces baseadas no duck typing. Nesta lição, você vai dominar todos os conceitos fundamentais da programação orientada a objetos no Go e aprenderá a usar interfaces para construir um sistema de gateway de pagamentos múltiplos com capacidade de alternância.

1. Você aprenderá


2. A história real de um engenheiro de pagamentos no comércio eletrônico

(1) Problema: O código “文” está codificado de forma rígida; adicionar um novo gateway de pagamento exige a modificação do código principal.

Charlie é engenheiro de back-end em uma plataforma de comércio eletrônico. Ele é responsável pela manutenção de um módulo de pagamentos:

“Nós oferecemos suporte ao Stripe e agora queremos adicionar o PayPal. Mas o código de pagamento está cheio de if gateway == "stripe", então adicionar o PayPal significaria reescrever o arquivo inteiro.”

Ele abriu o código escrito por seu antecessor:

GO
// Bad code: Hard-coded payment logic
func charge(amount float64, gateway string) error {
    switch gateway {
    case "stripe":
        // Stripe HTTP API calls...
        return stripeCharge(amount)
    case "paypal":
        // Adding PayPal means I have to add another case here.
        return nil
    default:
        return fmt.Errorf("unknown gateway: %s", gateway)
    }
}

Sempre que um gateway de pagamento é adicionado, a função charge precisa ser modificada — o que viola o Princípio Aberto-Fechado (aberto para extensão, fechado para modificação).

(2) A solução do Go: implementação implícita de interface

GO
// payment.go
package main

import "fmt"

// Define the Payment Interface
type PaymentGateway interface {
    Charge(amount float64) error
    Refund(transactionID string) error
}

// Stripe Implementation (No need to write "implements"!)
type Stripe struct {
    apiKey string
}

func (s Stripe) Charge(amount float64) error {
    fmt.Printf("Stripe: charged $%.2f\n", amount)
    return nil
}

func (s Stripe) Refund(txID string) error {
    fmt.Printf("Stripe: refunded %s\n", txID)
    return nil
}

// PayPal Implementation
type PayPal struct {
    email string
}

func (p PayPal) Charge(amount float64) error {
    fmt.Printf("PayPal: charged $%.2f\n", amount)
    return nil
}

func (p PayPal) Refund(txID string) error {
    fmt.Printf("PayPal: refunded %s\n", txID)
    return nil
}

// Consumer Code: Depends only on the interface, not on the concrete impl
func processPayment(gw PaymentGateway, amount float64) error {
    return gw.Charge(amount)
}

func main() {
    stripe := Stripe{apiKey: "sk_test_xxx"}
    paypal := PayPal{email: "merchant@example.com"}

    // The same processPayment Função can accept different concrete types.
    processPayment(stripe, 99.99)
    processPayment(paypal, 49.99)
}

Resultado:

TEXT 📖 Somente leitura
Stripe: charged $99.99
PayPal: charged $49.99

(3) Benefícios: O Princípio do Aberto-Fechado

Método Adicionar um novo gateway Modificar o código principal Risco
código fixo no switch Modificar a função charge ✅ Obrigatório 🔴 Alto
Abstração de interface Criar uma nova estrutura para implementar a interface ❌ Não é necessário 🟢 Baixo
💡 Dica: As interfaces no Go são implementadas implicitamente — desde que uma struct possua todos os métodos definidos em uma interface, ela “automaticamente” implementa essa interface. Isso é mais flexível do que o implements do Java: é possível até mesmo fazer com que tipos de pacotes de terceiros implementem interfaces definidas em pacotes externos.


3. Definições de métodos

(1) Método = uma função com um receptor

GO
package main

import "fmt"

type Rectangle struct {
    Width  float64
    Height float64
}

// Method: The receiver (r Rectangle) is placed between the func keyword and the function name
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func main() {
    rect := Rectangle{Width: 10, Height: 5}
    fmt.Printf("Area: %.2f\n", rect.Area())  // Area: 50.00
}

(2) Receptores de valor x receptores de ponteiro

GO
package main

import "fmt"

type Counter struct {
    Value int
}

// Value receiver: operates on a copy; does not affect the original object
func (c Counter) IncrementValue() Counter {
    c.Value++
    return c
}

// Pointer receiver: directly modifies the original object
func (c *Counter) IncrementPointer() {
    c.Value++
}

func main() {
    c := Counter{Value: 10}

    // Value receiver must use the return value
    c = c.IncrementValue()
    fmt.Printf("After value receiver: %d\n", c.Value)

    // Pointer receiver modifies directly
    c.IncrementPointer()
    fmt.Printf("After pointer receiver: %d\n", c.Value)
}

Resultado:

TEXT 📖 Somente leitura
After value receiver: 11
After pointer receiver: 12

(3) ▶ Exemplo: Escolha entre receptores de valor e de ponteiro

GO
package main

import "fmt"

type User struct {
    Name string
    Age  int
}

// Value receiver: suitable for small objects and read-only operations
func (u User) Info() string {
    return fmt.Sprintf("%s (%d)", u.Name, u.Age)
}

// Pointer receiver: suitable for large objects and modification operations
func (u *User) SetName(name string) {
    u.Name = name
}

type LargeData struct {
    data [1000]int
}

// Large structures must use pointer receivers (to avoid copying 1000 ints)
func (l *LargeData) Process() int {
    sum := 0
    for _, v := range l.data {
        sum += v
    }
    return sum
}

func main() {
    u := User{Name: "Alice", Age: 28}
    u.SetName("Alice Smith")
    fmt.Println(u.Info())

    ld := LargeData{}
    for i := 0; i < 1000; i++ {
        ld.data[i] = i
    }
    fmt.Printf("Sum: %d\n", ld.Process())
}
▶ Experimente

Resultado:

TEXT 📖 Somente leitura
Alice Smith (28)
Sum: 499500

(4) Guia para escolher entre receptores de valor e de ponteiro

Cenário Tipo de receptor Motivo
O método não modifica o receptor Tanto valores quanto ponteiros são aceitáveis Os receptores de valor são mais seguros (sem efeitos colaterais)
O método precisa modificar o receptor Ponteiro Um receptor de valor modifica uma cópia
Estruturas grandes (> 100 bytes) Ponteiro Evite copiar objetos grandes
O receptor é um map/slice/func Valores (que são tipos de referência) Já é uma referência
O tipo é um tipo primitivo Valor (não é necessário ponteiro) Pequeno, com baixo custo de cópia

4. Interfaces: Implementação implícita (Duck Typing)

(1) Definição da interface

GO
// Define an interface: a set of method signatures
type Stringer interface {
    String() string
}

(2) ▶ Exemplo: Implementação implícita

GO
package main

import "fmt"

// 1. Define an interface
type Speaker interface {
    Speak() string
}

// 2. Define two structs, both of which implement the Speak method
type Dog struct{ Name string }

func (d Dog) Speak() string {
    return fmt.Sprintf("%s says: Woof!", d.Name)
}

type Cat struct{ Name string }

func (c Cat) Speak() string {
    return fmt.Sprintf("%s says: Meow!", c.Name)
}

// 3. Consumer function: accepts an interface
func greet(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    dog := Dog{Name: "Buddy"}
    cat := Cat{Name: "Whiskers"}

    // Both Dog and Cat implicitly implement Speaker; the implements keyword is not required.
    greet(dog)
    greet(cat)
}
▶ Experimente

Resultado:

TEXT 📖 Somente leitura
Buddy says: Woof!
Whiskers says: Meow!

(3) Valores de interface: tipo dinâmico + valor dinâmico

GO
package main

import "fmt"

type Speaker interface {
    Speak() string
}

type Dog struct{ Name string }

func (d Dog) Speak() string {
    return fmt.Sprintf("%s says: Woof!", d.Name)
}

func main() {
    var s Speaker          // interface variable, defaults to nil
    fmt.Printf("nil: %T, %v\n", s, s)

    s = Dog{Name: "Buddy"} // interface stores dynamic type and dynamic value
    fmt.Printf("type=%T, value=%v\n", s, s)
}

Resultado:

TEXT 📖 Somente leitura
nil: <nil>, <nil>
type=main.Dog, value={Buddy}

5. A interface vazia interface{} e as asserções de tipo

(1) Interface vazia: qualquer tipo

GO
package main

import "fmt"

type Dog struct {
    Name string
}

// An empty interface can store any type
func describe(v interface{}) {
    fmt.Printf("type=%T, value=%v\n", v, v)
}

func main() {
    describe(42)
    describe("hello")
    describe(3.14)
    describe(Dog{Name: "Buddy"})
}

Resultado:

TEXT 📖 Somente leitura
type=int, value=42
type=string, value=hello
type=float64, value=3.14
type=main.Dog, value={Buddy}

(2) ▶ Exemplo: Asserção de tipo (sintaxe com vírgula)

GO
package main

import "fmt"

func printValue(v interface{}) {
    // Type assertion: extract underlying value
    if s, ok := v.(string); ok {
        fmt.Printf("String: %s (len=%d)\n", s, len(s))
        return
    }
    if n, ok := v.(int); ok {
        fmt.Printf("Int: %d (double=%d)\n", n, n*2)
        return
    }
    fmt.Printf("Unknown type: %T = %v\n", v, v)
}

func main() {
    printValue("hello")
    printValue(42)
    printValue(3.14)
}
▶ Experimente

Resultado:

TEXT 📖 Somente leitura
String: hello (len=5)
Int: 42 (double=84)
Unknown type: float64 = 3.14

(3) Seletor de tipo

GO
package main

import "fmt"

func inspect(v interface{}) {
    switch val := v.(type) {
    case string:
        fmt.Printf("string: %q (len=%d)\n", val, len(val))
    case int:
        fmt.Printf("int: %d\n", val)
    case float64:
        fmt.Printf("float64: %.2f\n", val)
    case bool:
        fmt.Printf("bool: %v\n", val)
    default:
        fmt.Printf("unknown: %T\n", val)
    }
}

func main() {
    inspect("hello")
    inspect(42)
    inspect(3.14)
    inspect(true)
    inspect([]int{1, 2, 3})
}

Resultado:

TEXT 📖 Somente leitura
string: "hello" (len=5)
int: 42
float64: 3.14
bool: true
unknown: []int

(4) Asserções de tipo x Seletores de tipo

Cenário Recomendação
Verificar se é um determinado tipo Asserção de tipo v.(T)
Marcar vários tipos Seletor de tipo v.(type)
Basta marcar (não é necessário inserir nenhum valor) _, ok := v.(T)

6. Composição de interfaces

(1) Criar uma nova interface incorporando uma interface existente

GO
package main

import "fmt"

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

type Writer interface {
    Write(p []byte) (n int, err error)
}

// Combine Reader and Writer to form a new interface
type ReadWriter interface {
    Reader
    Writer
}

// Implementation
type File struct{}

func (f File) Read(p []byte) (n int, err error) {
    return len(p), nil
}

func (f File) Write(p []byte) (n int, err error) {
    return len(p), nil
}

func main() {
    var rw ReadWriter = File{}
    buf := make([]byte, 10)
    rw.Read(buf)
    rw.Write(buf)
    fmt.Println("ReadWriter composite interface works as expected")
}

(2) ▶ Exemplo: Aplicação prática da composição de interfaces

GO
package main

import "fmt"

type Logger interface {
    Log(message string)
}

type Notifier interface {
    Notify(message string)
}

// Composition
type LoggerNotifier interface {
    Logger
    Notifier
}

type ConsoleService struct{}

func (c ConsoleService) Log(message string) {
    fmt.Printf("[LOG] %s\n", message)
}

func (c ConsoleService) Notify(message string) {
    fmt.Printf("[NOTIFY] %s\n", message)
}

func main() {
    var svc LoggerNotifier = ConsoleService{}
    svc.Log("System startup")
    svc.Notify("User Alice logged in")
}
▶ Experimente

Resultado:

TEXT 📖 Somente leitura
[LOG] System startup
[NOTIFY] User Alice logged in

(3) Referência rápida aos métodos de composição de interfaces

Combinação Sintaxe Descrição
Incorporando uma única interface type A interface { B } A contém todos os métodos de B
Incorporação de múltiplas interfaces type A interface { B; C } A contém todos os métodos de B e C
Incorporação + Novos métodos type A interface { B; C; Do() } A contém os métodos B, C e Do

7. As interfaces padrão io.Reader e io.Writer

(1) As duas interfaces mais essenciais da biblioteca padrão

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

type Writer interface {
    Write(p []byte) (n int, err error)
}

(2) ▶ Exemplo: Implementação do Reader de várias maneiras

GO
package main

import (
    "fmt"
    "io"
    "strings"
)

func printReader(r io.Reader) {
    buf := make([]byte, 8)
    for {
        n, err := r.Read(buf)
        if err == io.EOF {
            break
        }
        fmt.Printf("read: %q\n", buf[:n])
    }
}

func main() {
    // strings.Reader implements io.Reader
    fmt.Println("=== strings.Reader ===")
    printReader(strings.NewReader("hello world"))

    // You can also use bytes.Reader, os.File, etc.
}
▶ Experimente

Resultado:

TEXT 📖 Somente leitura
=== strings.Reader ===
read: "hello wo"
read: "rld"

(3) A combinação io.Reader + io.Writer (a cadeia da biblioteca padrão)

GO
package main

import (
    "fmt"
    "io"
    "strings"
)

func main() {
    // Implementing a copy using io.Reader and io.Writer
    reader := strings.NewReader("hello Go interfaces")
    writer := &strings.Builder{}

    // io.Copy accepts any Reader and Writer
    n, _ := io.Copy(writer, reader)
    fmt.Printf("copied %d bytes: %q\n", n, writer.String())
}

Resultado:

TEXT 📖 Somente leitura
copied 19 bytes: "hello Go interfaces"

(4) Lista de tipos padrão que implementam io.Reader

Tipo Pacote Implementa
strings.Reader strings Leitor
bytes.Reader bytes Leitor
os.File sistema operacional Leitor + Gravador
bytes.Buffer bytes Leitor + Gravador
net.Conn rede Leitor + Gravador
gzip.Reader compactar/gzip Leitor

8. Exemplo completo: Abstração de gateway de pagamentos múltiplos

Vamos reunir todos os conceitos-chave desta lição para construir um sistema de pagamento completo:

GO
// payment_system.go
package main

import (
    "fmt"
    "time"
)

// ---------- Interface Definition ----------

type PaymentGateway interface {
    Charge(amount float64) (string, error)     // Returns transaction ID
    Refund(transactionID string) error
    Name() string
}

// Logging Interface (Composition Example)
type TransactionLogger interface {
    Log(transactionID, gateway string, amount float64, success bool)
}

// ---------- Stripe Implementation ----------

type Stripe struct {
    apiKey string
}

func (s Stripe) Charge(amount float64) (string, error) {
    txID := fmt.Sprintf("STRIPE-%s", s.txID())
    fmt.Printf("[Stripe] charging $%.2f -> %s\n", amount, txID)
    return txID, nil
}

func (s Stripe) Refund(txID string) error {
    fmt.Printf("[Stripe] refunding %s\n", txID)
    return nil
}

func (s Stripe) Name() string {
    return "Stripe"
}

func (Stripe) txID() string {
    return fmt.Sprintf("%d", time.Now().UnixNano())
}

// ---------- PayPal Implementation ----------

type PayPal struct {
    email string
}

func (p PayPal) Charge(amount float64) (string, error) {
    txID := fmt.Sprintf("PP-%s", p.txID())
    fmt.Printf("[PayPal] charging $%.2f -> %s\n", amount, txID)
    return txID, nil
}

func (p PayPal) Refund(txID string) error {
    fmt.Printf("[PayPal] refunding %s\n", txID)
    return nil
}

func (p PayPal) Name() string {
    return "PayPal"
}

func (PayPal) txID() string {
    return fmt.Sprintf("%d", time.Now().UnixNano())
}

// ---------- Alipay Implementation ----------

type Alipay struct {
    appID string
}

func (a Alipay) Charge(amount float64) (string, error) {
    txID := fmt.Sprintf("ALI-%s", a.txID())
    fmt.Printf("[Alipay] charging $%.2f -> %s\n", amount, txID)
    return txID, nil
}

func (a Alipay) Refund(txID string) error {
    fmt.Printf("[Alipay] refunding %s\n", txID)
    return nil
}

func (a Alipay) Name() string {
    return "Alipay"
}

func (Alipay) txID() string {
    return fmt.Sprintf("%d", time.Now().UnixNano())
}

// ---------- Log Implementation (Empty Interface + Type Assertion Example) ----------

type ConsoleLogger struct{}

func (c ConsoleLogger) Log(transactionID, gateway string, amount float64, success bool) {
    status := "SUCCESS"
    if !success {
        status = "FAILED"
    }
    fmt.Printf("[%s] %s | %s | $%.2f | %s\n",
        status, transactionID, gateway, amount, time.Now().Format(time.RFC3339))
}

// ---------- Payment Service ----------

type PaymentService struct {
    gateway PaymentGateway
    logger  TransactionLogger
}

func NewPaymentService(gw PaymentGateway, logger TransactionLogger) *PaymentService {
    return &PaymentService{gateway: gw, logger: logger}
}

func (s *PaymentService) Charge(amount float64) error {
    txID, err := s.gateway.Charge(amount)
    if err != nil {
        s.logger.Log("", s.gateway.Name(), amount, false)
        return err
    }
    s.logger.Log(txID, s.gateway.Name(), amount, true)
    return nil
}

func (s *PaymentService) SwitchGateway(gw PaymentGateway) {
    fmt.Printf("\nSwitch payment gateway: %s -> %s\n", s.gateway.Name(), gw.Name())
    s.gateway = gw
}

// ---------- main ----------

func main() {
    logger := ConsoleLogger{}
    stripe := Stripe{apiKey: "sk_test_xxx"}
    paypal := PayPal{email: "merchant@example.com"}
    alipay := Alipay{appID: "2025xxxx"}

    // Start with Stripe
    service := NewPaymentService(stripe, logger)
    service.Charge(99.99)
    service.Charge(49.99)

    // Switch to PayPal at runtime (flexibility provided by the interface)
    service.SwitchGateway(paypal)
    service.Charge(199.99)

    // Switch to Alipay
    service.SwitchGateway(alipay)
    service.Charge(299.99)
}

Resultado esperado:

TEXT 📖 Somente leitura
[Stripe] charging $99.99 -> STRIPE-1741500000000
[SUCCESS] STRIPE-1741500000000 | Stripe | $99.99 | 2026-07-08T10:00:00Z
[Stripe] charging $49.99 -> STRIPE-1741500000001
[SUCCESS] STRIPE-1741500000001 | Stripe | $49.99 | 2026-07-08T10:00:00Z

Switch payment gateway: Stripe -> PayPal
[PayPal] charging $199.99 -> PP-1741500000002
[SUCCESS] PP-1741500000002 | PayPal | $199.99 | 2026-07-08T10:00:00Z

Switch payment gateway: PayPal -> Alipay
[Alipay] charging $299.99 -> ALI-1741500000003
[SUCCESS] ALI-1741500000003 | Alipay | $299.99 | 2026-07-08T10:00:00Z
100%
classDiagram
    class PaymentGateway {
        <<interface>>
        +Charge(amount float64) (string, error)
        +Refund(transactionID string) error
        +Name() string
    }
    class Stripe {
        -apiKey string
        +Charge(amount float64) (string, error)
        +Refund(transactionID string) error
        +Name() string
    }
    class PayPal {
        -email string
        +Charge(amount float64) (string, error)
        +Refund(transactionID string) error
        +Name() string
    }
    class Alipay {
        -appID string
        +Charge(amount float64) (string, error)
        +Refund(transactionID string) error
        +Name() string
    }
    class PaymentService {
        -gateway PaymentGateway
        -logger TransactionLogger
        +Charge(amount float64) error
        +SwitchGateway(gw PaymentGateway)
    }
    PaymentGateway <|.. Stripe : implicit impl
    PaymentGateway <|.. PayPal : implicit impl
    PaymentGateway <|.. Alipay : implicit impl
    PaymentService o--> PaymentGateway : depends on interface (Strategy Pattern)
🔥 Erro comum: O campo gateway em PaymentService é um tipo de interface, não um tipo concreto. Uma variável de interface pode conter qualquer valor que implemente essa interface — essa é a base da implementação do Padrão de Estratégia na linguagem Go.


❓ Perguntas Frequentes

P: Como escolho entre tipos de receptor por valor e por ponteiro? R: Três regras: (1) Se o receptor precisar ser modificado → ponteiro; (2) Estruturas grandes (> 100 bytes) → ponteiro; (3) Em todos os outros casos, dê preferência a receptores por valor. Se um tipo usar um receptor por ponteiro, recomenda-se que todos os métodos sigam a mesma convenção.

P: Como devo entender a implementação implícita de interfaces? R: Desde que uma estrutura (struct) possua todas as assinaturas de métodos definidas em uma interface, ela implementa automaticamente essa interface — sem a necessidade da palavra-chave implements. Isso significa que: (1) Tipos de pacotes de terceiros também podem implementar as interfaces que você definir; (2) Um único tipo pode implementar várias interfaces completamente independentes entre si.

P: Qual é a finalidade da interface vazia interface{}? R: Ela aceita valores de qualquer tipo. Casos de uso comuns: (1) fmt.Println(a ...interface{}); (2) armazenamento de valores de diferentes tipos em um mapa: map[string]interface{}; (3) desserialização de dados (análise de JSON em interface{}).

P: O que devo fazer se uma asserção de tipo falhar? R: Use a sintaxe “comma-ok”: v, ok := x.(T). Não ocorrerá um panico se ok for falso. Se você não usar a sintaxe “comma-ok”, uma asserção com falha causará um panico: v := x.(string) causará um panico se x não for uma string.

P: Qual é a diferença entre composição de interfaces e estruturas aninhadas? R: (1) Composição de interfaces → Combina assinaturas de métodos (reutilização de comportamento); (2) Estruturas aninhadas → Combina campos e métodos (reutilização de dados). A composição de interfaces se enquadra na “abstração comportamental”, enquanto as estruturas aninhadas se enquadram na “agregação de dados”.

P: Os valores de interface são tipos de valor ou tipos de referência? R: Os valores de interface são tipos de referência. Uma variável de interface armazena internamente um par (tipo, valor) — quando um valor é atribuído a ela, é esse par que é copiado, e não os dados subjacentes. Portanto, passar valores de interface como parâmetros é muito leve (apenas 2 ponteiros).

P: Quando o método Read de io.Reader retorna EOF? R: Quando todos os dados tiverem sido lidos, Read retorna (0, io.EOF). Observe que EOF indica um fim normal, não um erro — portanto, você não pode usar err != nil para verificar se a leitura foi concluída; é necessário usar err == io.EOF.

P: Um tipo pode implementar várias interfaces ao mesmo tempo? R: Sim. Desde que um tipo possua todos os métodos de várias interfaces, ele as implementa implicitamente. Essa também é uma das principais vantagens do design de interfaces do Go — composição flexível sem uma hierarquia de herança.


📖 Resumo


📝 Exercícios

  1. Problema básico (Dificuldade ⭐): Defina a interface Shape (Area() float64), implemente duas estruturas — Circle (raio) e Rectangle (largura e altura) — e calcule e imprima suas áreas.

  2. Problema Avançado (Dificuldade ⭐⭐): Implemente uma interface Cache (Get(key string) (interface{}, bool) / Set(key string, value interface{})), utilizando map[string]interface{} e uma versão com restrição de memória (máximo de 10 chaves) para implementar duas estratégias diferentes. É necessário utilizar receptores de ponteiro.

  3. Problema de desafio (Dificuldade ⭐⭐⭐): Implemente um backend de armazenamento plugável: Defina a interface Store (Save(key string, data []byte) error / Load(key string) ([]byte, error) / Delete(key string) error), implemente MemoryStore (armazenamento em mapa) e FileStore (armazenamento em arquivo usando os.WriteFile / os.ReadFile) e, por fim, use um BackupService para sincronizar os dados entre os dois tipos de armazenamento.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%