Service locators allow you to remove required data from an interface of an object and instead get these data from a secondary object - the service locator.

We normally have direct dependency declarations in APIs:

    class A(data1: B, data2: C)
    {
    }

Compare this to using a service locator:

    class A(locator: L)
    {
        data1 = locator.locate_data1();
        data2 = locator.locate_data2();
    }
Where code internal to the A acquires B and C from the locator.

Drawbacks

The biggest drawback with a service locator is that we now make dependencies implicit. Depending on whether your locator default-constructs locatables on non-existence or not, your program can also start failing dynamically instead of statically.

Advantages

This pattern is useful if we need provide dependencies to a heterogeneous set of classes all with their own peculiar dependencies, while these classes are all created in a uniform way. An example is providing input data to a set of heterogeneous types.
    let v: Collection<dyn SomeInterface> = ...;

    let locator = ...;

    for a in v {
        v.use_locator(locator):
    }