在Dart中,double.infinity和double.maxFinite有什么区别?

14

double.infinity和double.maxFinite在Dart中有什么区别?

在Flutter中,它们看起来都是做同样的事情。在Flutter中应该如何使用它们?


4
它们在概念上代表着不同的事物。 double.infinity 代表着无穷大。 double.maxFinite 代表着一个 double 可以存储的最大值,但它 不是 无穷大。 - jamesdlin
3个回答

5

从一个严格的数据导向角度来看,区别在于 double.maxFinite 表示 double 数据类型可以包含的最大允许值,而 double.infinity 则表示无穷大。由于Dart在所有平台上都将 double 严格定义为64位浮点数,因此 double.maxFinite 的值被确定为 1.7976931348623157e+308。(具体原因可能相当技术性,但jpopesculian的答案部分涉及了一些内容,总体来说,对于简单的应用程序开发,理解这些细节通常并不是必需的。)

在Flutter中,大多数情况下,这两个值之间没有太大的实际差异。你通常会在调整小部件大小时使用这些常量,并且当你希望小部件尽可能大时,你可以将宽度和/或高度设置为 double.infinity

SizedBox(
  width: 500,
  height: 500,
  child: Container(
    width: double.infinity,
    height: double.infinity,
  ),
)

在这个例子中,子Container被赋予了无限的宽度和高度。Flutter会通过使用其父级来确定实际可用空间并对其进行约束来计算其大小。在这种情况下,Container受到SizedBox的限制,SizedBoxContainer施加了500像素乘以500像素的硬限制 - 无论Container请求多少空间,它都不能超过这个大小。因此,将double.infinity替换为double.maxFinite不会改变任何东西,因为父级SizedBox仍然只允许它变得如此大。
这通常是这样的,因为Flutter中的大多数布局小部件都带有某种隐式约束,要么作为其功能的一部分,要么从其父级继承(最终将是类似于MaterialAppScaffold的东西,将其子级约束为屏幕的大小)。因此,大多数情况下,试图比可用空间更大的子级不会成为太大的问题,因为Flutter的布局规则足够强大,可以防止它们占用超过允许的空间。
有一些情况下,无限约束可能会导致问题。拿这个非常牵强的例子来说吧:
Column(
  children: [
    Container(
      height: double.infinite,
    ),
  ],
)

在这里,我们有一个具有创建无限大垂直空间效果的Column。作为它的子元素,它有一个请求无限高度的Container。问题很明显:Flutter如何将一个无限高的小部件约束在具有无限约束的父部件中?确实如此,尝试渲染此小部件会产生以下错误:
════════ Exception caught by rendering library ═════════════════════════════════ 
The following assertion was thrown during performLayout():
BoxConstraints forces an infinite height.

所以,如果问题是无限大小的小部件无法存在于无限约束的空间中,那么如果我们将 double.infinity 更改为 double.maxFiniteContainer 中会怎么样?这将解决问题,因为 Container 不再是无限大小的,Flutter 可以正常计算其约束:

Column(
  children: [
    Container(
      height: double.maxFinite,
      color: Colors.red,
    ),
  ],
)

成功!无限高度约束错误已经消失!

...我们只是得到了这个错误:

════════ Exception caught by rendering library ═════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 1.7976931348623157e+308 pixels on the bottom.

所以,尽管现在高度被正确计算了,Column如果其子项的高度超过可用空间,将会出现问题。事实证明,对于现代屏幕来说,大约一百个百亿像素太高了。[需要引用]

(对于那些好奇的人来说,这里的解决方案是将Container包装在Expanded中,它将占据Column中的可见空间,并再次强制执行有限约束,限制Container不超过允许的空间。[或者,你知道的,你也可以不创建如此庞大的小部件。])

总之,在使用Flutter中的double.infinity的地方,通常double.infinitydouble.maxFinite之间没有实际区别。但在偶尔有区别的情况下,你通常只会把一个问题换成另一个问题。

所有这些都需要说,大部分的Flutter小部件库都是以`double.infinity`作为潜在的有效输入而编写的,因此在大多数情况下,您要么会得到明确定义的行为,要么会得到详细的错误消息。然而,对于`double.maxFinite`的使用,我预计将得到较少直接支持,所以尽管它有时可能仍然有效,但在不适用的情况下,您可能无法得到非常清晰的反馈,了解出了什么问题。因此,总体而言,只需在适当的地方使用`double.infinity`,而在其他地方,请坚持使用对我们凡人来说更有意义的数值。

非常感谢这篇精彩的帖子!它帮助我更好地理解Flutter中的尺寸调整方式。 - undefined

1
为了理解两者之间的区别,我认为重要的是要了解浮点数(double)的存储方式。(免责声明:我将使用16位来解释,忽略字节序,但实际上Dart将根据平台使用32位或64位。)
作为参考,16位定点数(int)的存储方式如下:
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
 | |___________________________________________|
 |                      |
 v                      v
sign bit            magnitude

第0位是符号(0表示正数,1表示负数),其余位是幅值,例如实际数字。因此,-142看起来像1000000010001110

相比之下,浮点数(double)的存储方式如下:

 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
 | |__________||_______________________________|
 |          |                  |
 v          v                  v
sign bit   exponent        fraction

第0位是符号位,接下来的4位是指数,最后的位数是小数部分。表示的公式如下:

n = (sign) * 2^(exponent - 7) * (1 + fraction)

其中分数是2的倒数幂之和。例如,0100001100000000表示

sign = 1 // positive because byte 0 is 0
exponent = 8 // 1000 as a decimal
fraction = 0.375 // 0*2^-1 + 1*2^-2 + 1*2^-3 + 0*2^-4 + 0*2^-5 ... 

n = 2.75 // 1 * 2^(8-7) * (1 + 0.375)

此外,该标准将允许在给定某些指数的情况下表示特殊值。

使用指数0000,我们可以表示更小的数字“次正常”数字。

n = (sign) * 2^-6 * (0 + fraction)

指数为1111时,如果小数部分为零,则可以表示正无穷或负无穷。例如,0111100000000000表示正无穷。如果小数部分不为零,则变成NaN或非数字。

因此,回答您的问题,double.infinity表示0111100000000000double.maxFinite表示0011111111111111。这也可能有助于解释其他常量,如double.nandouble.minPositive,它表示0000000000000001


0

区别可以概括为:

  • 我想要尽可能大,但也受到父级限制(double.infinity)

一些小部件允许它们的子元素尽可能大

ColumnListViewOverflowBox 在这种情况下使用double.infinity

根据文档,这些是分配给各种double常量的值。

static const double infinity = 1.0 / 0.0;
static const double negativeInfinity = -infinity;
static const double minPositive = 5e-324;
static const double maxFinite = 1.7976931348623157e+308;

希望这回答了你的问题


11
你没有提到任何 double.maxFinite 可用的情况,在两种情况下都使用了 double.infinity - iDecode
我该如何获取屏幕的总高度,然后进行相应的调整? - ᴅ ᴇ ʙ ᴊ ᴇᴇ ᴛ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接