在 R 中使用整数值而不是数值(例如 1L 与 1)作为常量的好处

Benefits of using integer values for constants rather than numeric values (e.g. 1L vs 1) in R

在 R 源代码中,大多数(但不是全部)函数使用整数值作为常量:

colnames <- function(x, do.NULL = TRUE, prefix = "col")
{
    if(is.data.frame(x) && do.NULL)
    return(names(x))
    dn <- dimnames(x)
    if(!is.null(dn[[2L]]))
    dn[[2L]]
    else {
        nc <- NCOL(x)
    if(do.NULL) NULL
        else if(nc > 0L) paste0(prefix, seq_len(nc))
        else character()
    }
}

R Language Definition 说:

In most cases, the difference between an integer and a numeric value will be unimportant as R will do the right thing when using the numbers. There are, however, times when we would like to explicitly create an integer value for a constant.

问题是关于良好做法和基本原理,而不是关于例如。 the "L" notation itself, the difference between integer class and numeric class, or comparing numbers.

这些是我在声明常量时明确使用 L 后缀的一些用例。当然,这些并不是严格意义上的“规范”(或唯一的),但也许您可以了解背后的基本原理。我为每种情况添加了一个“必要”标志;你会发现这些只有在你接触其他语言(如 C)时才会出现。

  • 逻辑类型转换(不需要)

我没有使用经典的 as.integer,而是使用将 0L 添加到逻辑向量以使其成为整数。当然,您可以只使用 0,但这需要更多内存(通常是 8 个字节而不是四个字节)和转换。

  • 操作returns整数(不需要)
  • 的函数的结果

例如,您想要在 NA 之后查找以检索向量的元素。你可以:

which(is.na(vec)) + 1L

由于 which returns 和 integer,添加 1L 将保留类型并避免隐式转换。如果您省略 L,则不会发生任何事情,因为它只是一个小的优化。例如,match 也会发生这种情况:如果您想 post 处理此类函数的结果,最好尽可能保留类型。

  • 接口 C(必需)

来自 ?integer:

Integer vectors exist so that data can be passed to C or Fortran code which expects them, and so that (small) integer data can be represented exactly and compactly.

C 在数据类型方面要严格得多。这意味着,如果将向量传递给 C 函数,则不能依赖 C 来进行转换。假设你想用某个值替换 NA 之后的元素,比如 42。你找到 NA 值在 R 级别的位置(就像我们之前用 which 所做的那样),然后传递原始向量和C 的索引向量。C 函数如下所示:

SEXP replaceAfterNA (SEXP X, SEXP IND) {
   ...
   int *ind = INTEGER(IND);
   ...
   for (i=0; i<l; i++) {
        //make here the replacement
   }
}

R 侧:

...
ind <- which(is.na(x)) + 1L
.Call("replaceAfterNA", x, ind)
...

如果您在上面的第一行中省略了 L,您将收到如下错误:

INTEGER() cannot be applied to double vectors

因为 C 需要整数类型。

  • 接口Java(必需)

和以前一样。如果你使用了rJava包并且想让R调用你自己自定义的Java类和方法,你必须确保在Java方法需要时传递的是一个整数一个整数。此处不添加具体示例,但应该清楚为什么在这些情况下您可能希望在常量中使用 L 后缀。

附录

之前的案例中您可能想要使用 L。即使我猜不太常见,添加一个您 不想要 L 的案例可能会有用。如果存在整数 溢出 的危险,则可能会出现这种情况。如果两个操作数都是整数,则 *+- 运算符会保留类型。例如:

#this overflows
31381938L*3231L
#[1] NA
#Warning message:
#In 31381938L * 3231L : NAs produced by integer overflow

#this not
31381938L*3231
#[1] 1.01395e+11

因此,如果您正在对可能产生溢出的整数变量进行操作,请务必将其转换为 double 以避免任何风险。 Adding/subtracting 给那个变量一个没有 L 的常量可能是进行转换的好时机。