来自R大神著作《Advanced R 》练习题,来一起检验一下R语言知识吧!🤓
本文参考资料:
《Advanced R》中文版
《Advanced R 》英文版
Advanced R 知乎专栏
Tips:
R 入门基础电子书推荐:
https://bookdown.org/xiangyun/RGraphics/file-manipulation.html
进一步了解R ,应该看一下《advanced R 》原文教材,对于理解R逻辑很重要,比如为什么sum("TRUE")=1 ?
笔记只是很少很少的一部分知识,如果感兴趣请阅读 《Advanced R 》英文版
目录:
2.数据结构
3.取子集操作
4.词汇表
5.编码风格
6.函数
7.面向对象
8.环境
9.调试
2.数据结构
小测验
做这个简短的测试来确定你是否需要阅读本章。 如果你很快就能想到答案,那么
你可以轻松地跳过这一章。 答案在 2.5 节。
- 除了包含的数据以外,向量的三个性质是什么?
- 四种常见的原子向量类型是什么? 两种罕见的类型是什么?
- 属性是什么? 如何存取属性?
- 原子向量和列表有什么不同? 矩阵和数据框有什么不同?
- 列表也可以是矩阵吗? 数据框能把矩阵作为一列数据吗?
2.5 答案
- 向量的三个性质是:类型、长度和属性。
- 四种常用的原子向量类型是:逻辑型、整数型、双精度浮点数型(有时称作数
值型)和字符型。 两种罕见类型是:复数类型和 raw 类型。 - 属性可以让你在任意对象上附加任意元数据。 你可以通过 attr(x, "y")和 attr(x,
"y") <- value 来存取单个属性;或者通过 attributes()存取所有属性。 - 列表中的元素可以是任意类型,包括列表类型本身。 原子向量的所有元素都是相同的类型;在一个数据框中,不同列可以包含不同类型。
- 你可以通过在列表中设置维度属性的方式来创建列表数组(list-array)。 你可以使用 df$x<- matrix(),让一个矩阵作为数据框的一列,或者在创建一个新数据框时使用 I()函数,例如 data.frame(x = I(matrix())。
本章概要
2.1 节介绍原子向量、列表、 R 的一维数据结构。
2.2 节将讨论属性, R 语言的灵活的元数据规范。 你将学习因子类型: 一种重要的数据结构,它是通过设置原子向量的属性而得来的。
2.3 节介绍了矩阵和数组: 用来存储 2 维或更高维数据的数据结构。
2.4 节介绍数据框:在 R 语言中存储数据最重要的数据结构。 数据框把列表和矩阵的行为结合起来,使得这种结构适合统计数据的需要。
2.1.3 练习
- 原子向量的六种类型是什么? 列表和原子向量的区别是什么?
- is.vector()和 is.numeric()与 is.list()和 is.character()的根本区别是什么?
- 推测下面 c()函数的强制转换结果:
c(1, FALSE)
c("a", 1)
c(list(1), "a")
c(TRUE, 1L)
- 为什么要使用 unlist()把列表转换为原子向量? 为什么不能使用 as.vector()?
- 为什么 1 == "1"为 TRUE? 为什么-1 < FALSE 为 TRUE? 为什么"one" < 2 为
FALSE? - 为什么默认缺失值 NA 是一个逻辑向量? 逻辑向量有什么特殊的地方吗? (提
示: 想想 c(FALSE,NA_character_)。 )
2.2.2 练习
- 以下代码定义了一个结构,使用了 structure()函数:
structure(1:5, comment = "my attribute")
#> [1] 1 2 3 4 5
但是,当你打印该对象的时候,却看不到 comment 属性。 这是为什么呢? 是属性缺失,或者是其它原因呢? (提示:尝试使用帮助文档。 )
- 当你修改因子的水平时,会发生什么?
f1 <- factor(letters)
levels(f1) <- rev(levels(f1))
- 这段代码起了什么作用? f2 和 f3 与 f1 相比,有什么区别?
f2 <- rev(factor(letters))
f3 <- factor(letters, levels = rev(letters))
2.3.1 练习
- 对向量使用 dim()函数时,会返回什么?
- 如果 is.matrix(x)返回 TRUE,那么 is.array(x)会返回什么?
- 如何描述以下三个对象? 它们使得 1:5 有什么不同?
x1 <- array(1:5, c(1, 1, 5))
x2 <- array(1:5, c(1, 5, 1))
x3 <- array(1:5, c(5, 1, 1))
2.4.5 练习
- 数据框拥有哪些属性?
- 某个数据框包含不同数据类型的列,对其使用 as.matrix()时,会发生什么?
- 可以创建 0 行的数据框吗? 0 列的呢?
3 取子集操作
小测验
做个简短的测试来确定你是否需要阅读这一章。 如果你能很快地想到答案,那么你可以轻松地跳过这一章。 答案在第 3.5 节。
- 用正整数、负整数、逻辑向量或字符向量对向量进行取子集操作的结果是什么?
- 当应用于列表时, [、 [[和$的区别是什么?
- 在什么时候你应该使用 drop = FALSE?
- 如果 x 是一个矩阵,那么 x[] <- 0 会做什么? 它和 x <- 0 有什么不同?
- 怎样使用已命名的向量,为分类变量重新贴上标签(relabel categorical
variables)?
3.5 答案
- 正整数选择在特定位置的元素,负整数删除元素;逻辑向量选择对应位置为
TRUE 的元素,字符向量选择与元素名字匹配的元素。 - [选择子列表。 它总是返回列表;如果你使用单个正整数来执行它,则返回长
度为 1 的列表。 [[选择列表中的元素。 y 等价于
x[["y"]]。 - 如果你对矩阵、数组或数据框执行取子集操作,那么当你希望保持原始维度
的时候,可以使用 drop = FALSE。 在函数内部执行取子集操作时,则应该总
是设置该参数。 - 如果 x 是一个矩阵,那么 x[] <- 0 将把所有的元素替换为 0,并保持相同的行
数和列数。 x <- 0 则完全把矩阵替换成了数值 0。 - 已命名的字符向量可以当做一个简单的查询表: c(x = 1, y = 2, z = 3)[c("y", "z",
"x")]
本章概要
第 3.1 节从教你使用[开始。 你将学习六种可以为原子向量进行取子集操作的数据。 然后,你将学习为列表、矩阵、数据框和 S3 对象进行取子集操作时,这六种数据类型是如何工作的。
第 3.2 节扩充你在取子集操作符方面知识,包括[[和$,并关注于"简化"和"保持"的重要原则。
在第 3.3 节,你将学习为子集赋值的方法,它们把取子集操作和赋值操作结合起来,以便修改对象的一部分。
第 3.4 节通过八个重要但是不太明显的取子集操作的应用示例,来帮助你解决在数据分析中经常碰到的问题
3.1.7 练习
- 下列代码试图对数据框进行取子集操作,但是都有错误,请修改:
mtcars[mtcars$cyl = 4, ]
mtcars[-1:4, ]
mtcars[mtcars$cyl <= 5]
mtcars[mtcars$cyl == 4 | 6, ]
- 为什么 x <- 1:5; x[NA]产生了 5 个缺失值? (提示:为什么与 x[NA_real_]不
同? ) upper.tri()函数返回什么? 它是怎样对矩阵进行取子集操作的? 我们需要其
它取子集操作的规则来描述它的行为吗?
x <- outer(1:5, 1:5, FUN = "*")
x[upper.tri(x)]
- 为什么 mtcars[1:20]返回错误? 它跟看起来很相似的 mtcars[1:20, ]有什么不
同? - 实现一个函数,它将取出矩阵主对角线上的元素(它应该与 diag(x)函数表现相
似的行为,其中 x 是一个矩阵)。 - 语句 df[is.na(df)] <- 0 做了什么? 它是如何做的?
3.2.4 练习
- 给定一个线性模型,比如 mod <- lm(mpg ~ wt, data = mtcars),取出残差自由
度(the residual degrees of freedom)。 从模型的汇总信息(summary(mod))
中取出 R 方(R-squared)的值。
3.4.9 练习
- 如何随机排列数据框的列? (这是在随机森林中的一个重要技术。 ) 你能在一
步之中同时排列行和列吗?R 语言高级程序设计 70 - 如何在数据框中选择一个 m 行随机样本? 如果要求样本是连续的(比如,给定
一个开始行、一个结束行,得到它们之间的所有行),应该怎么做呢? - 怎样把数据框中的列按照字母顺序进行排序?
4 词汇表
挑选出最有用的R函数
4.1 基础
# 首先要学习的函数
?
str
# 重要的运算符和赋值函数
%in%, match
=, <-, <<-
$, [, [[, head, tail, subset
with
assign, get
# 比较
all.equal, identical
!=, ==, >, >=, <, <=
is.na, complete.cases
is.finite
# 基本数学函数
*, +, -, /, ^, %%, %/%
abs, sign
acos, asin, atan, atan2
sin, cos, tan
ceiling, floor, round, trunc, signif
exp, log, log10, log2, sqrt
max, min, prod, sum
cummax, cummin, cumprod, cumsum, diff
pmax, pmin
range
mean, median, cor, sd, var
rle
# 用于函数的函数
function
missing
on.exit
return, invisible
# 逻辑和集合
&, |, !, xor
all, any
intersect, union, setdiff, setequal
which
# 向量和矩阵
c, matrix
# 自动强制转换规则 character > numeric > logical
length, dim, ncol, nrow
cbind, rbind
names, colnames, rownames
t
diag
sweep
as.matrix, data.matrix
# 创建向量
c
rep, rep_len
seq, seq_len, seq_along
Vocabulary 59
rev
sample
choose, factorial, combn
(is/as).(character/numeric/logical/...)
# 列表和数据框
list, unlist
data.frame, as.data.frame
split
expand.grid
# 控制流
if, &&, || (short circuiting)
for, while
next, break
switch
ifelse
# apply 族函数
lapply, sapply, vapply
apply
tapply
replicat
4.2 通用数据结构
# 日期与时间
ISOdate, ISOdatetime, strftime, strptime, date
difftime
julian, months, quarters, weekdays
library(lubridate)
# 字符操作
grep, agrep
gsub
strsplit
chartr
nchar
tolower, toupper
substr
paste
library(stringr)
# 因子
factor, levels, nlevels
reorder, relevel
cut, findInterval
interaction
options(stringsAsFactors = FALSE)
# 数组操作
array
dim
dimnames
aperm
library(abind)
4.3 统计学
# 排序与制表
duplicated, unique
merge
order, rank, quantile
sort
table, ftable
# 线性模型
fitted, predict, resid, rstandard
lm, glm
hat, influence.measures
logLik, df, deviance
formula, ~, I
anova, coef, confint, vcov
contrasts
# 其它测试
apropos("\\.test$")
# 随机变量
(q, p, d, r) * (beta, binom, cauchy, chisq, exp, f, gamma, geom, hyper, lnorm, logis, mul
tinom, nbinom, norm, pois, signrank, t, unif, weibull, wilcox, birthday, tukey)
# 矩阵代数
crossprod, tcrossprod
eigen, qr, svd
%*%, %o%, outer
rcond
solve
4.4 使用 R 语言工作
# 工作空间
ls, exists, rm
getwd, setwd
q
source
install.packages, library, require
# 帮助
help, ?
help.search
apropos
RSiteSearch
citation
demo
example
vignette
# 调试
traceback
browser
recover
options(error = )
stop, warning, message
tryCatch, try
4.5 输入/输出
# 输出
print, cat
message, warning
dput
format
sink, capture.output
# 读写数据
data
count.fields
read.csv, write.csv
read.delim, write.delim
read.fwf
readLines, writeLines
readRDS, saveRDS
load, save
library(foreign)
# 文件和路径
dir
basename, dirname, tools::file_ext
file.path
path.expand, normalizePath
file.choose
file.copy, file.create, file.remove, file.rename, dir.create
file.exists, file.info
tempdir, tempfile
download.file, library(downloader)
5.编码风格指南
基于《谷歌 R 代码风格指南》(http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html)
6 函数
小测验
回答下列问题,判断你是否可以跳过本章。 答案在第 6.7 节。
- 函数包含哪三个组成部分?
- 下列代码返回什么?
y <- 10
f1 <- function(x) {
function() {
x + 10
} }
f1(1)()
- 在什么情况下,你更需要写如下代码?
`+`(1, `*`(2, 3))
- 怎样让下面的函数调用更具有可读性?
mean(, TRUE, x = c(1:10, NA))
- 调用下列函数时,会抛出错误吗? 为什么会/不会?
f2 <- function(a, b) {
a * 10
}
f2(10, stop("This is an error!"))
- 什么是中缀函数? 怎样编写中缀函数? 什么是替换函数? 怎样编写替换函
数? - 使用什么函数来确保清理动作的执行,无论函数怎样终止时,都会调用它?
6.7 小测验答案
- 函数的三个组成部分是函数体、 参数列表和环境。
- f1(1)()返回 11。
- 通常写成中缀形式: 1 + (2 * 3)。
- 重写的调用形式 mean(c(1:10, NA), na.rm = TRUE)更容易理解。
- 不,它不会抛出错误,因为第二个参数是从未使用过的,所以它并没有进行计
算。 - 看第 6.5.1 节和第 6.5.2 节。
- 使用 on.exit();更详细的描述看第 6.6.1 节。
本章概要
第 6.1 节描述了函数的三个主要组成部分。
第 6.2 节教你 R 语言如何通过名字找到值 —— 词法作用域的过程。
第 6.3 节向你展示,所有在 R 语言中发生的事情都是函数调用的结果,即使看起
来不像。
第 6.4 节讨论给函数提供参数的三种方式,以及如何通过提供参数列表来调用函数,以及延迟计算的影响。
第 6.5 节描述了两种特殊类型的函数: 中缀函数和替换函数。
第 6.6 节讨论函数如何返回值,以及何时返回值,以及如何可以确保在函数退出之前做一些事情。
6.1.2 练习
- 什么函数可以告诉你一个对象是不是函数? 什么函数可以告诉你一个函数是
不是原语函数? - 这段代码创建了 base 包中的所有函数的列表。
objs <- mget(ls("package:base"), inherits = TRUE)
funs <- Filter(is.function, objs)
使用它来回答下面的问题:
a. base 包中的哪一个函数拥有最多的参数?
b. base 包中的有多少个函数没有参数? 这些函数有什么特点?c. 怎样修改这段代码,使得它能找到所有的原语函数? - 函数中的三种重要组成部分是什么?4. 在什么情况下打印一个函数,它被创建时所处的环境不会显示出来?
6.2.5 练习
- 下列代码返回什么? 为什么? 这些 c 分别代表什么含义?
c <- 10
c(c = c)
- R 语言查找对象值的四条原则是什么?
- 下列函数返回什么? 在运行代码前,自己先判断一下。
f <- function(x) {
f <- function(x) {
f <- function(x) {
x ^ 2
} f
(x) + 1
} f
(x) * 2
}
f(10)
6.4.6 练习
- 说明下面一些列奇怪的函数调用:
x <- sample(replace = TRUE, 20, x = c(1:10, NA))
y <- runif(min = 0, max = 1, 20)
cor(m = "k", y = y, u = "p", x = x)
- 这个函数返回什么? 为什么? 它说明了什么原则?
f1 <- function(x = {y <- 1; 2}, y = 0) {
x + y
}
f1()
- 这个函数返回什么? 为什么? 它说明了什么原则?
f2 <- function(x = z) {
z <- 100
x }
f2()
6.5.3 练习
- 创建一个列表,里面包含了所有 base 包中的替换函数。 其中哪些是原语函<br />
数? - 什么样的名字对用户创建的中缀函数是有效的?
- 创建中缀形式的 xor()运算符。
- 创建中缀版的集合操作函数 intersect()、 union()和 setdiff()。
- 创建一个替换函数,它可以随机修改向量中的某个位置的元素。
6.6.2 练习
- source()的 chdir 参数如何与 in_dir()进行比较? 与其它方法相比,说说你为
什么更喜欢你选择的方法? - 什么函数可以解除 library()的操作? 如何保持和恢复 options()和 par()的值?
- 编写一个函数,它会打开一个图形设备,然后运行提供的代码,最后关闭图形
设备(要求无论绘图的代码是否工作,总是会执行)。 - 我们可以使用 on.exit()来实现一个简单的版本 capture.output()。
capture.output2 <- function(code) {
temp <- tempfile()
on.exit(file.remove(temp), add = TRUE)
sink(temp)
on.exit(sink(), add = TRUE)
force(code)
readLines(temp)
}
capture.output2(cat("a", "b", "c", sep = "\n"))
#> [1] "a" "b" "c"
比较 capture.output()和 capture.output2()。 这两个函数有什么不同? 为了让关键思想更容易被看到,我删除了什么特性? 为了更容易理解,我是如何重写关键思想的?
7 面向对象指南
小测验
认为你知道这些内容了吗? 如果你能正确地回答下面的问题,那么你可以跳过本章。 答案在 7.6 节。
- 怎样说明一个对象关联到了什么面向对象系统(基本、 S3、 S4 或 RC)?
- 如何确定一个对象的基本类型(如整型或列表)?
- 什么是泛型函数?
- S3 和 S4 之间的主要区别是什么? S4 和 RC 之间的主要区别是什么?
7.6 小测验答案
- 要确定对象的面向对象系统,可以使用排除法。 如果!is.object(x),那么它是
基本对象。 如果!isS4(x),那么它是 S3 对象。 如果!is(x, "refClass"),那么它
是 S4 对象;否则,它就是引用类对象。 - 使用 typeof()来确定对象的基类。
- 一个泛型函数根据输入的类调用特定方法。 在 S3 和 S4 对象系统中,方法属
于泛型函数,而不是像其它编程语言一样属于类。 - S4 比 S3 更加正式,并且支持多重继承和多分派。 引用类对象具有引用语
义,它的方法属于类,而不是函数。
本章概要
7.1 节教你 R 语言的基本对象系统。 只有 R-core 团队才能在这个系统中添加新类,但是了解它是很重要的,因为它支撑着其它三种系统。
7.2 节向你展示了 S3 对象系统的基础知识。 它是最简单和最常用的面向对象系统。
7.3 节讨论了更加正式和严格的 S4 系统。
7.4 节教你 R 语言的最新面向对象系统: 引用类,或简称为 RC。
7.5 节给你一些建议,当你开始一个新的项目时,应该选择哪种面向对象系统。
7.2.5 练习
- 阅读 t()和 t.test()的源代码,并确定 t.test()是一个 S3 泛型函数而不是一个 S3
方法。 如果你创建一个名为 test 的类的对象,并调用了 t(),会发生什么? - 在基础 R 语言中,有哪些类拥有 Math 组泛型函数的方法? 阅读源代码。 这
些方法是如何工作的? - R 语言有两种代表日期时间数据的类, POSIXct 和 POSIXt,它们都继承自
POSIXlt。 哪些泛型函数对这两种类有不同的行为? 哪些泛型函数有同样的行
为? - 哪一个基础的泛型函数拥有最多的方法?
- UseMethod()使用一种特殊的方式来调用方法。 预测下面的代码将返回什么,
然后运行它,并阅读 UseMethod()的帮助,指出发生了什么。 尽量以最简单
的形式把规则写下来。
y <- 1
g <- function(x) {
y <- 2
UseMethod("g")
}
g.numeric <- function(x) yg(10)
h <- function(x) {
x <- 10UseMethod("h")
}
h.character <- function(x) paste("char", x)
h.numeric <- function(x) paste("num", x)h("a")
- 内部泛型函数不会对基本类型的隐式类分派方法。 仔细阅读?"internal
generic",并确定为什么下例中 f 和 g 的长度是不同的。 哪个函数有助于区分
f 和 g 的行为呢?
f <- function() 1
g <- function() 2
class(g) <- "function"
class(f)
class(g)
length.function <- function(x) "function"
length(f)
length(g)
7.3.5 练习
- 哪一个 S4 泛型函数拥有最多的为它定义的方法? 哪一个 S4 类拥有最多的与
它关联的方法? - 如果你定义了一个新的 S4 类,但是并没有包含现有的类,会发生什么? (提
示:使用?Classes 了解一下虚类(virtual classes)。 ) - 如果你把 S4 对象传给 S3 泛型函数,会发生什么? 如果你将 S3 对象传给 S4
泛型函数, 会发生什么? (提示:第二种情况可以阅读?setOldClass)。
7.4.4 练习
- 使用一个字段函数(field function)来阻止直接对帐户余额的操作。 (提示:创
建一个"隐藏的"余额(.balance)字段,并且阅读在 setRefClass()中关于字段参数
的帮助文档)。 - 我曾说在基础的 R 语言中,不存在任何引用类,这个有点过于简单化了。 使
用 getclass()找到哪些类是从 envRefClass 类继承扩展(extend())而来的。 这些
类是作为什么来使用的? (提示:回忆一下如何查找一个类的帮助文档)。
8 环境
小测验
如果你能正确回答下列问题,那么你已经知道了本章中最重要的话题。 你可以在末尾的 8.6 节找到答案。
- 列出至少三个方面来说明环境是不同于列表的。
- 全局环境的父环境是什么? 哪种独一无二的环境是没有父环境的?
- 函数的封闭环境是什么? 为什么它很重要?
- 如何确定一个函数调用所处的环境?
- <-和<<-有什么不同?
8.6 小测验答案
- 有四种方式:一个环境中的每个对象都必须有一个名称;顺序无关紧要;环境
有父环境;环境具有引用语义。 - 全局环境的父环境是上一个加载的包。 唯一没有父环境的环境是空环境。
- 函数的封闭环境是它被创建时所处的环境。 它决定了函数在哪里查找变量。
- 使用 parent.frame()。
- <-总是在当前环境下创建一个绑定; <<-在当前环境的父环境中,重新绑定一
个现有的名字。
本章概要
8.1 节介绍环境的基本属性,并向你展示怎样创建环境。
8.2 节提供了一个带着环境进行计算的函数模板,并用一个有用的函数来说明这个
思路。
8.3 节更深入地修正了 R 的作用域规则,显示它们如何对应于环境的四种类型,而
这些环境是与每个函数相关联的。
8.4 节描述了名称必须遵循的规则,并显示了一些把名称绑定到一个值的方式。
8.5 节讨论了三个问题,环境是有用的数据结构,在作用域中具有独立的作用。
8.1.1 练习
- 列出环境与列表三个不同的地方。
- 如果你没有提供显式的环境,那么 ls()和 rm()会在哪里搜索? <-会在哪里创
建绑定关系? - 使用 parent.env()和循环(或者递归函数),验证 globalenv()的祖先包括
baseenv()和 emptyenv()。 使用相同的基本思路实现你自己的 search()函数。
8.2.1 练习
- 修改 where()函数,使它找到包含以某个名字命名的绑定关系的所有环境。
- 使用编写 where()函数的风格,来编写你自己版本的 get()函数。
- 写一个称为 fget()的函数,它只寻找函数对象。 它应该有两个参数, name 和
env,应该遵守针对函数的普通作用域规则:如果存在一个名字匹配的对象,
但是并不是函数,那么继续搜索父环境。 另一个挑战,添加一个 inherits 参
数,它控制着函数是否递归到父环境,或者仅仅搜索一个环境。 - 写一个你自己的 exists(inherits = FALSE)函数(提示:使用 ls())。 写一个类似
于 exists(inherits = TRUE)的递归版本的函数。
8.3.5 练习
- 列出与一个函数相关的四种环境。 每种环境分别是做什么用的? 为什么封闭
环境和绑定环境的区别特别重要? - 画一个图,显示这个函数的封闭环境:
f1 <- function(x1) {
f2 <- function(x2) {
f3 <- function(x3) {
x1 + x2 + x3
}f3(3)
}f2(2)
}f1(1)
- 扩展上面的图,以显示函数绑定。
- 再次扩展上面的图,以显示执行环境和调用环境。
- 写一个增强版的 str()函数,使它提供更多关于函数的信息。 显示函数是在哪
里被发现的,以及它是在什么环境中定义的。
8.4.1 练习
- 这个函数是做什么的? 它与<<-有什么不同,你为什么更应该喜欢它?
rebind <- function(name, value, env = parent.frame()) {
if (identical(env, emptyenv())) {
stop("Can't find ", name, call. = FALSE)
} else if (exists(name, envir = env, inherits = FALSE)) {
assign(name, value, envir = env)
} else {
rebind(name, value, parent.env(env))
} }
rebind("a", 10)
#> Error: Can't find a
a <- 5
rebind("a", 10)
a
#> [1] 10
-
创建另一个版本的 assign()函数,它只会绑定新名称,而永远不会重新绑定旧
名称。 有一些编程语言只能这样做,它们被称为单赋值语言。
http://en.wikipedia.org/wiki/Assignment_(computer_science)#Single_assign -
编写一个赋值函数,它可以进行活动绑定、 延迟绑定以及锁定(locked)绑定。
你该给它取什么名字呢? 它应该接受什么参数呢? 你能根据输入猜出是哪种
类型的赋值吗?
网友评论