如何在内部锁定对所有结构域的并发访问?

How to lock concurrent access to all struct fields internally? Let's say I have a struct:

 type Data struct {
    ID string
    Size int
    //... and more fields
 }

That will be used in another struct:

type Project struct {
    mu sync.Mutex
    MetaData Data
    //... and more fields
}

How could I modify/get MetaData struct and use mutex for that while not exposing its mutex to the outer packages? I know I could use Get/Set methods, but what if I needed to modify one field of Data struct (it wouldn't be very good/clean if every field had a get/set method with the same shared mutex)? Could you recommend a way/pattern to have a struct-wise mutex that would be locked/unlocked internally?

How about something like this?

type Data struct {
    ID   string
    Size int
    //... and more fields
}

type Project struct {
    mu       sync.Mutex
    metaData Data
    //... and more fields
}

func (p *Project) AccessMetaData(f func(*Data)) {
    p.mu.Lock()
    defer p.mu.Unlock()
    f(&p.metaData)
}

I was curious about this so I tested this, and if the parent struct is locked, the child struct is also locked. Try it locally as go playground seems to be deterministic.

package main

import (
    "fmt"
    "sync"
)

type testGroup struct {
    sync.Mutex
    items map[string]*test
}

type test struct {
    x int
}

var str string = "test"

func increment(t *testGroup, wg *sync.WaitGroup) {
    t.Lock()
    t.items[str].x = t.items[str].x + 1
    t.Unlock()
    wg.Done()
}

func main() {
    var w sync.WaitGroup
    tg := testGroup{}
    tg.items = make(map[string]*test)
    tg.items[str] = &test{}
    for i := 0; i < 1000; i++ {
        w.Add(1)
        go increment(&tg, &w)
    }
    w.Wait()
    fmt.Println("final value of x", tg.items[str].x)
}

Try commenting out t.Lock() and t.Unlock() in increment() function