为啥不接受 Map 构造函数的可迭代元组数组?
Posted
技术标签:
【中文标题】为啥不接受 Map 构造函数的可迭代元组数组?【英文标题】:Why doesn't accept the Map constructor an Array of iterable tuples?为什么不接受 Map 构造函数的可迭代元组数组? 【发布时间】:2017-10-21 07:18:27 【问题描述】:我在 javascript 中创建了一个元组类型,它实现了Iterable
协议。现在应该很容易转换为Map
:
const Tuple = (...args) =>
const Tuple = f => f(...args);
Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
return Tuple;
;
new Map([Tuple(1, "a"), Tuple(2, "b")]); // Map undefined => undefined
我必须手动进行转换:
const Tuple = (...args) =>
const Tuple = f => f(...args);
Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
return Tuple;
;
const toArray = tx => tx((...args) => args);
const Map_ = (...pairs) =>
return new Map(pairs.map(pair => toArray(pair)));
;
const map = Map_(Tuple(1, "a"), Tuple(2, "b"));
console.log(map.get(1), map.get(2)); // "a" "b"
似乎Map
只接受外部复合类型的Iterable
,而不接受内部对。我错过了什么?有没有其他方法可以实现转换?
【问题讨论】:
每次创建Tuple
时创建两个函数,您支持什么设计目标?
不变性;避免使用Array
s 来存储各种类型的相关数据(例如[a, b]
)。 Array
是一个集合,因此应该是 [a]
类型。
不变性不需要您为每个 Tuple
创建多个函数。
哦,是的,你是对的,它是教堂编码的。当然,不必如此。
“它是教堂编码的” 有趣!
【参考方案1】:
Map
的构造函数被定义为接受任何可迭代的键/值对象,其中键/值对象被定义为属性0
是键,属性1
是值的对象。它没有说明允许对键/值对象使用 Iterables。 (如果它确实允许它们并定义它会准确地调用迭代器两次,那可能会很酷,但是......那不是他们所做的。:-) 而且它会更多复杂...)
如果我们查看the spec,如果它支持属性0
(用于键)和1
(用于值),您的Tuple
将起作用。例如:
// (Defined this way because you seemed to want a non-constructor)
const TupleMethods =
get "0"()
return this.key;
,
get "1"()
return this.value;
;
const Tuple = (key, value) =>
const t = Object.create(TupleMethods);
t.key = key;
t.value = value;
return t;
// Usage:
const m = new Map([
Tuple("one", "uno"),
Tuple("two", "due"),
Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"
您在评论中提到了不变性。也许:
// (Defined this way because you seemed to want a non-constructor)
const TupleMethods = ;
Object.defineProperties(TupleMethods,
"0":
get()
return this.key;
,
"1":
get()
return this.value;
);
const Tuple = (key, value) =>
const t = Object.create(TupleMethods);
Object.defineProperties(t,
key:
value: key
,
value:
value: value
);
return t;
;
// Usage:
const m = new Map([
Tuple("one", "uno"),
Tuple("two", "due"),
Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"
【讨论】:
这很有意义。谢谢!【参考方案2】:const Tuple = (...args) => Object.entries([args.shift()]: args.shift());
const map = new Map(Tuple(0, "a").concat(Tuple(1, "b")));
console.log(map.get("0"), map.get("1"));
【讨论】:
【参考方案3】:我在 Javascript 中创建了一个元组类型,它实现了
Iterable
协议。
不要。元组具有固定长度的独特属性,每个元素都有(可以有)自己的类型,而(可迭代的)集合由 same 类型的多个元素组成。当然 JavaScript 不关心类型(所有数组都是异构的),但是作为程序员的你应该关心。
为什么
Map
只接受外部复合类型的Iterable
,而不接受内部对?
出于完全相同的原因。元素是 pairs 或二元组,表示为数组(因为缺少另一种数据结构,并且不必像迭代器结果那样引入一个简单的数据结构)。它们总是有两个元素,可以通过[0]
和[1]
访问(它们甚至不需要.length
!),绝对没有理由重复它们。
【讨论】:
我知道元组通常是不可折叠的。我只是让它们可迭代,以便它们可以很好地与Array.from
和Map
一起使用。但是,我不明白 Map
构造函数是如何在幕后工作的。现在它很有意义!
@ftor Array.from
也适用于具有整数属性和 .length
的对象。不过,我不明白为什么或如何从元组创建 Map
。
也许我在这里走错了路。我认为从[(k, v)]
转换为Map k v
以及反之亦然是明智之举。但是,我对元组没有太多经验。
是的,我以为你的意思是 new Map(Tuple([k1, v1], [k2, v2], …))
元组需要是可迭代的。对于Array.from(Tuple(…))
和new Map([Tuple(k1, v1), Tuple(k2, v2), …])
,您只需要0
、1
和length
三个属性。
对不起,没有。我只是假设“accepts an Iterable
”也指的是内部对 [[k, v]]
。但是,当这些对的结构简单明了且众所周知时,为什么要这样做。我将尝试为我的下一个问题提供类型签名。无论如何,我已经习惯为我的所有功能定义它们。事实证明,当我在表达类型信号方面遇到困难时,我经常会最终丢弃相应的函数。它是一个函数是否有用的一个很好的指标——即使在无类型语言中也是如此。以上是关于为啥不接受 Map 构造函数的可迭代元组数组?的主要内容,如果未能解决你的问题,请参考以下文章
c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?