I'm right now also assuming that a UAV can only be used in things such as "StructuredBuffers" and "ByteAddressBuffers" but I don't quite understand what those are either.
Nope, they're for SRV's that have been created from buffer resources (as opposed to the more common case of SRV's that have been created from texture resources).
These are simply for when you want a shader to be able to perform random-access reads from a buffer resource.
As an example, AMD GPU's do not actually have very much in the way of "input assembler" hardware any more. When you bind a vertex buffer to the IA stage, the driver is actually patching your vertex shader code to contain some Buffer/StructuredBuffer variables, and automagically binds SRV's for your vertex buffers to the VS stage. The magic (driver-generated) VS code can then read the vertex attributes out of the buffers as required.
If you ever need to read data out of a buffer in a shader, you can use Buffer HLSL variables too. Buffer is for simple types, like float4 / R32G32B32A32_FLOAT, while StructuredBuffer is for structs (like cbuffers). If you ever need to bind a massive array of data to a shader -- like a skeleton for vertex skinning, then buffers are probably a better choice than cbuffers.
Lastly ByteAddressBuffers simply let you read 32-bit values without any automatic format decoding -- the DIY buffer view.
UAV's are for RWStructuredBuffers and RWByteAddressBuffers, so best to understand the above use case first :)
UAV's are similar to SRV's, but in HLSL you use these RW* types, and bind them to u# registers instead of t# registers. The big difference is that you can also write to these resource views!
e.g. normally in a shader you sample texels from a texture -- but a UAV lets you write data into the texture, such as:
myTexture[x,y] = float4(1,0,0,0);
Also, what are counter buffers
In D3D11, a UAV can be created with a counter attached to it (it's handled internally by D3D), but in D3D12 it's a bit more manual to implement this, hence the extra type in D12 (you make two buffers - one for the UAV to read/write data from, and one for the counter)...
The counters are used by AppendBuffers and ConsumeBuffers. These are buffers that you can write data to / read data from like a stack. E.g. if a shader is spawning particles, it can push them into an append buffer. The counter keeps track of how many particles were pushed.
Later on, a particle rendering shader can use a consume buffer to pop items from that stack (and reduce the counter).
These are used in places where shaders should generate a variable amount of data.