在java中,你可以做类似的事情
UUID id = UUID.fromString("eb66c416-4739-465b-9af3-9dc33ed8eef9");
long msb = id.getMostSignificantBits();
long lsb = id.getLeastSignificantBits();
System.out.println(msb + ", " + lsb);
// -1484283427208739237, -7281302710629372167
System.out.println(new UUID(msb, lsb));
// eb66c416-4739-465b-9af3-9dc33ed8eef9
这个相同的例子在另一个问题中被引用,它非常相似,所以这将是一个后续。虽然在 lsb, msb -> string 的相关问题中解决了,但我找不到反向问题的解决方案,string -> msb, lsb
原来的解决方案是
function toUuidString(lsb, msb) {
return `${digits(msb >> 32n, 8n)}-${digits(msb >> 16n, 4n)}-${digits(
msb,
4n
)}-${digits(lsb >> 48n, 4n)}-${digits(lsb, 12n)}`
}
function digits(value, ds) {
const hi = 1n << (ds * 4n)
return (hi | (value & (hi - 1n))).toString(16).slice(1)
}
现在我想要一个接受字符串并返回 msb 和 lsb 的函数。 沿着原始问题的路径,我发现了java源代码并尝试做等效的事情,这将是:
function fromString(name) {
let components = name.split('-')
if (components.length !== 5) {
throw new Error(`Invalid UUID string: ${name}`)
}
for (let index = 0; index < 5; index++) {
components[index] = `0x${components[index]}`
}
let mostSigBits = Number.parseInt(components[0], 16)
mostSigBits <<= 16
mostSigBits |= Number.parseInt(components[1], 16)
mostSigBits <<= 16
mostSigBits |= Number.parseInt(components[2], 16)
let leastSigBits = Number.parseInt(components[3], 16)
leastSigBits <<= 48
leastSigBits |= Number.parseInt(components[4], 16)
return {
leastSigBits,
mostSigBits,
}
}
但是,当我尝试用类似的东西来测试它时:
const originalUuid = 'eb66c416-4739-465b-9af3-9dc33ed8eef9'
const parts = fromString(originalUuid)
const newUUid = toUuidString(
BigInt(parts.leastSigBits),
BigInt(parts.mostSigBits)
)
console.log('Original', originalUuid)
console.log('New', newUUid)
我没有获得等效的 uuid。它们有相同的部件,但缺少一些部件
Original eb66c416-4739-465b-9af3-9dc33ed8eef9
New 00000000-4739-465b-ffff-ffffbefbeef9
有什么想法出了什么问题吗?
最后我发现了问题——两段代码并不是严格等价的,java源代码声明mostSigBits和leastSigBits一样长,这在javascript中无法表示,所以我们需要使用BigInt。
总结我的问题和之前的问题,java UUID 操作的 javascript 等效项是:
字符串 -> MSB、LSB
function fromString(name) {
let components = name.split('-')
if (components.length !== 5) {
throw new Error(`Invalid UUID string: ${name}`)
}
for (let index = 0; index < 5; index++) {
components[index] = `0x${components[index]}`
}
let mostSigBits = BigInt(Number.parseInt(components[0], 16))
mostSigBits <<= 16n
mostSigBits |= BigInt(Number.parseInt(components[1], 16))
mostSigBits <<= 16n
mostSigBits |= BigInt(Number.parseInt(components[2], 16))
let leastSigBits = BigInt(Number.parseInt(components[3], 16))
leastSigBits <<= 48n
leastSigBits |= BigInt(Number.parseInt(components[4], 16))
return {
leastSigBits,
mostSigBits,
}
}
msb、lsb -> 字符串(来自引用的问题)
function toUuidString(lsb, msb) {
return `${digits(msb >> 32n, 8n)}-${digits(msb >> 16n, 4n)}-${digits(
msb,
4n
)}-${digits(lsb >> 48n, 4n)}-${digits(lsb, 12n)}`
}
function digits(value, ds) {
const hi = 1n << (ds * 4n)
return (hi | (value & (hi - 1n))).toString(16).slice(1)
}
Java对UUID生成的实现是在java.lang.Long::fastUUID处实现的。它对长值使用无符号右移操作,而JavaScript的BigInt没有。
这里我实现了无符号位移右移操作,并复制了Java的fastUUID实现。
// fastUUID({msb: BigInt("-8432159880597844756"),
// lsb: BigInt("-5548517530057857892")})
//
// Should be the same as:
//
// new java.util.UUID(-8432159880597844756, -5548517530057857892)
//
// which is 8afaf343-9baa-4cec-b2ff-b4b426dfa49c