了解Kotlin let的需求

时间:2019-01-26 20:56:22

标签: kotlin let

我正试图了解为什么需要让。在下面的示例中,我有一个带有功能GiveMeFive的Test类:

public class Test() {
    fun giveMeFive(): Int {
        return 5
    }
}

给出以下代码:

var test: Test? = Test()

var x: Int? = test?.giveMeFive()

test = null

x = test?.giveMeFive()
x = test?.let {it.giveMeFive()}

x设置为5,然后将test设置为null后,调用以下任一语句返回x的null。鉴于在null引用上调用方法会跳过该调用并将x设置为null,为什么我需要使用let?在某些情况下只是?不能正常工作,需要租借吗?

此外,如果被调用的函数未返回任何内容,则为?。会跳过该呼叫,并且我也不需要?.let。

4 个答案:

答案 0 :(得分:4)

let()

fun <T, R> T.let(f: (T) -> R): R = f(this)

let()是作用域函数:每当您要为代码的特定范围定义变量时都可以使用它,但不能超出范围。使您的代码保持良好的独立性非常有用,这样您就不会有变量“泄漏出去”:可以通过它们应有的位置进行访问。

DbConnection.getConnection().let { connection ->
}

//连接在这里不再可见

let()也可以用作测试null的替代方法:

val map : Map<String, Config> = ...
val config = map[key]
// config is a "Config?"
config?.let {
// This whole block will not be executed if "config" is null.
// Additionally, "it" has now been cast to a "Config" (no 
question mark)
}

A simple go to chart when to use when.

答案 1 :(得分:2)

如果要链接未在链接类型上定义的函数调用,则需要使用// Not defined inside the Test class fun giveMeFive(t: Test) { return 5 }

比方说,您的函数的定义是这样的:

Test

现在,如果您有一个可为空的let,并且想在链中调用此函数,则必须使用val x = test?.let { giveMeFive(it) }

// Herokuapp.com has a root cert that won't parse:
// DigiCert SHA2 High Assurance Server CA.pem
// E (48067) esp-tls: mbedtls_x509_crt_parse returned -0x112c
static const char *heroku_server_root_cert_pem = "-----BEGIN CERTIFICATE-----\r\n\
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs\r\n\
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\r\n\
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\r\n\
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL\r\n\
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\r\n\
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy\r\n\
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2\r\n\
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC\r\n\
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1\r\n\
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn\r\n\
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X\r\n\
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft\r\n\
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA\r\n\
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\r\n\
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\r\n\
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t\r\n\
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG\r\n\
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ\r\n\
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D\r\n\
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd\r\n\
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH\r\n\
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly\r\n\
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu\r\n\
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF\r\n\
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae\r\n\
cPUeybQ=\r\n\
-----END CERTIFICATE----";

//Let's Encrypt Authority X3.pem
static const char *webhook_server_root_cert_pem = "-----BEGIN CERTIFICATE-----\r\n\
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\r\n\
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\r\n\
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\r\n\
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\r\n\
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n\
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\r\n\
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\r\n\
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\r\n\
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\r\n\
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\r\n\
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\r\n\
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\r\n\
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\r\n\
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\r\n\
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\r\n\
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\r\n\
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\r\n\
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\r\n\
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\r\n\
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\r\n\
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\r\n\
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\r\n\
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\r\n\
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\r\n\
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\r\n\
-----END CERTIFICATE-----";

static void parse_certs() {
   mbedtls_x509_crt *global_cacert = (mbedtls_x509_crt *)calloc(1, sizeof(mbedtls_x509_crt));
   if (global_cacert == NULL) {
     printf("global_cacert not allocated");
     return;
   }
  mbedtls_x509_crt_init(global_cacert);

  int ret;  

  ret = mbedtls_x509_crt_parse(global_cacert,
            (const unsigned char *) heroku_server_root_cert_pem,
            strlen(heroku_server_root_cert_pem) + 1);

  printf("Parse of herokuapp.com root cert is %d\n", ret);            

  ret = mbedtls_x509_crt_parse(global_cacert,
            (const unsigned char *) webhook_server_root_cert_pem,
            strlen(webhook_server_root_cert_pem) + 1);

  printf("Parse of webhook.site root cert is %d\n", ret);   
  free(global_cacert);         

}

答案 2 :(得分:1)

Kotlin中的.let {}扩展功能:

  1. 作为对象引用,作为调用.let{}的参数。

  2. 返回使用let{}函数返回的任何非原始数据类型的值。默认情况下,它返回undefined类的kotlin.Any值。

软件包kotlin中的声明:

public inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

简单的实际演示,以了解.let{}扩展功能在Kotlin中的工作方式。

示例代码1:-

val builder = StringBuilder("Hello ")
println("Print 0: $builder")

val returnVal = builder.let { arg ->
    arg.append("World")
    println("Print 1: $arg")

    "Done" // Returnning some string
}
println("Print 2: $builder")
println("Print 3: $returnVal")

示例代码1输出:-

Print 0: Hello 
Print 1: Hello World
Print 2: Hello World
Print 3: Done

在示例代码1中:

  1. 我们用初始化值“ Hello”创建了StringBuilder类型的最终对象。

  2. builder.let{}中,构建器对象引用将传递到arg

  3. 在这里,输出Print 2: Hello WorldPrint 3: Hello World表示builderarg都指向相同的StringBuilder {{1 }}。这就是为什么它们都打印相同的object-reference值的原因。

  4. String功能块的最后一行中,我们返回.let{} "Done"的值,该值将分配给String

*因此,我们从returnVal获得了Print 3: Done的输出。

示例代码2:-

returnVal

示例代码2输出:-

val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
    arg.append("World")
    println("Print 1: $arg")
    arg.length
    }

println("Print 2: $builder")
println("Print 3: $returnVal") // Now return val is int = length of string.

在示例代码2中:

有什么区别:

Print 0: Hello Print 1: Hello World Print 2: Hello World Print 3: 11 功能块的最后一行中,我们返回的.let{}值等于StringBuilder对象Int的长度,该对象在此代码行的值为{{1} }。因此,将arg类型的 length = "Hello World"分配给11

*因此,我们从Int得到returnVal

也可以尝试以下操作:-

  • .run(){}
  • .apply(){}
  • with(obj){}
  • .also(){}

快乐编码...

答案 3 :(得分:0)

有趣 T.let(f: (T) -> R): R = f(this)

.let 块不等于多线程

val x? = 空

if(x == null) {
}

x?.let{
}

.let 块是线程安全的